GitHub
github.com › wdahlenburg › werkzeug-debug-console-bypass
GitHub - wdahlenburg/werkzeug-debug-console-bypass: Werkzeug has a debug console that requires a pin. It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector. · GitHub
Werkzeug has a debug console that requires a pin by default. It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector.
Starred by 66 users
Forked by 8 users
Languages Python 85.8% | Dockerfile 14.2%
GitHub
github.com › wdahlenburg › werkzeug-debug-console-bypass › blob › main › werkzeug-pin-bypass.py
werkzeug-debug-console-bypass/werkzeug-pin-bypass.py at main · wdahlenburg/werkzeug-debug-console-bypass
It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector. - werkzeug-debug-console-bypass/werkzeug-pin-bypass.py at main · wdahlenburg/werkzeug-debug-console-bypass
Author wdahlenburg
Vulnlab
arz101.medium.com › hackthebox-agile-19a3559ad04a
HackTheBox — Agile - ARZ101 - Medium
August 4, 2023 - Agile involved using Local File Read (LFR) to read the source files with debug mode enabled, allowing to access werkzeug console by reading files responsible for generating PIN, having access to the console, getting a shell as www-data and escalating to corum user by accessing the database to retrieve the password, further escalating to edwards by port forwarding Selenium port to inspect a testing page of the application, getting the password and finally escalating to root by abusing python virtual environment activation script through sudoedit (CVE 2023–22809).
GitHub
github.com › wdahlenburg › werkzeug-debug-console-bypass › blob › main › server.py
werkzeug-debug-console-bypass/server.py at main · wdahlenburg/werkzeug-debug-console-bypass
Werkzeug has a debug console that requires a pin. It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector. - werkzeug-debug-console-bypass/server.py at main · wdahlenburg/werkzeug-debug-console-bypass
Author wdahlenburg
GitHub
github.com › grav3m1nd-byte › werkzeug-pin
GitHub - grav3m1nd-byte/werkzeug-pin: Yet another Werkzeug Console Pin Exploit Explanation · GitHub
As explained by Carlos Polop in Hacktricks.xyz, this exploit is to access /console from Werkzeug when it requires a pin.
Author grav3m1nd-byte
Werkzeug
werkzeug.palletsprojects.com › en › stable › debug
Debugging Applications — Werkzeug Documentation (3.1.x)
The first time a console is opened, a dialog will prompt for a PIN that is printed to the command line. The PIN is generated in a stable way that is specific to the project. An explicit PIN can be provided through the environment variable WERKZEUG_DEBUG_PIN. This can be set to a number and will become the PIN.
YouTube
youtube.com › watch
Agile HTB Walkthrough - Werkzeug Console PIN Exploit - YouTube
Agile is a Hack The Box machine hosting a password manager solution. A file read vulnerability in the application, combined with Flask running in debug mode,...
Published February 7, 2025
HackTricks
book.hacktricks.xyz › home › network services pentesting › pentesting web › werkzeug
Werkzeug / Flask Debug - HackTricks
3 days ago - The PIN generation mechanism can be studied from the Werkzeug source code repository, though it is advised to procure the actual server code via a file traversal vulnerability due to potential version discrepancies. To exploit the console PIN, two sets of variables, probably_public_bits and private_bits, are needed:
GitHub
github.com › calyeo › werkzeug-debug-console-bypass › blob › main › README.md
werkzeug-debug-console-bypass/README.md at main · calyeo/werkzeug-debug-console-bypass
Werkzeug has a debug console that requires a pin. It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector. - calyeo/werkzeug-debug-console-bypass
Author calyeo
GitHub
github.com › vignesh21-git › werkzeug_debug_bypass_POC
GitHub - vignesh21-git/werkzeug_debug_bypass_POC: Werkzeug Console PIN Exploit · GitHub
By exploiting the path traversal vulnerability and gathering system information, we successfully generate the debug pin required to access the Werkzeug debugger console remotely.
Author vignesh21-git
Greg Scharf
blog.gregscharf.com › 2023 › 04 › 09 › lfi-to-rce-in-flask-werkzeug-application
LFI to RCE in Flask Werkzeug Application :: Greg Scharf — Development & Security
April 10, 2023 - Second, check if the secret key used to sign session cookies is visible anywhere in the source code. Finally, check whether debugging has been enabled in Werkzeug when the application was started. If debugging is enabled, attempt to crack the PIN to access the debugging console and execute ...
CTFtime.org
ctftime.org › writeup › 36100
CTFtime.org / KnightCTF 2023 / Knight Search / Writeup
1. Remote Code Execution (RCE) Via Werkzeug Debug Console & Bypassing Console PIN Code, Path Traversal Filter
Daehee
daehee.com › blog › werkzeug-console-pin-exploit
Werkzeug Console PIN Exploit | Daehee Park
January 10, 2020 - They are unlikely to be contained anywhere # within the unauthenticated debug page. private_bits = [ str(uuid.getnode()), get_machine_id(), ] h = hashlib.md5() for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, text_type): bit = bit.encode('utf-8') h.update(bit) h.update(b'cookiesalt') cookie_name = '__wzd' + h.hexdigest()[:20] # If we need to generate a pin we salt it a bit more so that we don't # end up with the same value and generate out 9 digits if num is None: h.update(b'pinsalt') num = (' d' % int(h.hexdigest(), 16))[:9] # Format the pincode in groups of digits for easier remembering if # we don't have a result yet.
Medium
medium.com › @sharmaaakas16 › werkzeug-debugger-authentication-bypass-via-client-side-response-manipulation-d0f5a97b90f7
Werkzeug Debugger Authentication Bypass via Client-Side Response Manipulation | by AAKASH SHARMA | Medium
January 31, 2026 - I opened my proxy tool (Burp Suite), typed a random 4-digit PIN (1234), and hit submit. I intercepted the response from the server. The server responded with a JSON object: {"authenticated": false} This was the “aha!” moment. I noticed that the webpage didn’t refresh; it stayed on the same page and just displayed an error. This suggested that the client-side JavaScript was the one making the decision to show or hide the console based on that JSON value.
GitHub
github.com › wdahlenburg › werkzeug-debug-console-bypass › blob › main › README.md
werkzeug-debug-console-bypass/README.md at main · wdahlenburg/werkzeug-debug-console-bypass
Werkzeug has a debug console that requires a pin by default. It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector.
Author wdahlenburg
GitHub
github.com › wdahlenburg › werkzeug-debug-console-bypass › blob › main › app.py
werkzeug-debug-console-bypass/app.py at main · wdahlenburg/werkzeug-debug-console-bypass
Werkzeug has a debug console that requires a pin. It's possible to bypass this with an LFI vulnerability or use it as a local privilege escalation vector. - werkzeug-debug-console-bypass/app.py at main · wdahlenburg/werkzeug-debug-console-bypass
Author wdahlenburg
Gitbook
cel1s0.gitbook.io › offsec-notes › readme › linux-unix › werkzeug-console-pin-bypass
Werkzeug Console PIN bypass | OffSec Notes
import hashlib from itertools import chain import os import getpass pin = None rv = None num = None probably_public_bits = [ 'h4ckua11' , # username 'flask.app' , # modname 'Flask', '/usr/local/lib/python2.7/dist-packages/flask/app.py' ] private_bits = [ '191101483950643' , 'my serial number' ] h = hashlib.md5() # Bit is going through every thing in probably_public_bits and private_bits for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, unicode): bit = bit.encode("utf-8") h.update(bit) h.update(b"cookiesalt") if num is None : h.update(b"pinsalt") num = (" d" % int(h.hexdigest(), 16))[:9] if rv is None : for group_size in 5 , 4 , 3 : if len (num)% group_size == 0 : rv = '-' .join (num [x: x + group_size] .rjust (group_size, '0' ) for x in range ( 0 , len (num), group_size)) break else : rv = num print (rv)