Hacktricks-skills python-read-gadgets
Use Python internal read gadgets to extract secrets from vulnerable applications. Trigger this skill whenever the user mentions Python format string vulnerabilities, class pollution, Flask/Django secret extraction, Werkzeug debug console access, environment variable leakage, or any scenario where they have read-only access to Python internals but need to pivot to sensitive data. Also use when users ask about Python sandbox escapes, __globals__ traversal, sys.modules access, or CTF-style Python exploitation.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/generic-methodologies-and-resources/python/python-internal-read-gadgets/SKILL.MDPython Internal Read Gadgets
When you have read-only access to Python internals (via format strings, class pollution, or similar vulnerabilities), use these techniques to extract secrets and escalate privileges without code execution.
When to Use This Skill
- You've identified a Python format string vulnerability
- You have class pollution access in a Python application
- You need to extract Flask/Django/Werkzeug secrets
- You're working on a CTF with Python sandbox constraints
- You need to traverse
or__globals__
to reach sensitive datasys.modules
Core Concept
Different vulnerabilities like Python Format Strings or Class Pollution might allow you to read Python internal data but won't allow you to execute code. Your goal is to make the most of these read permissions to obtain sensitive privileges and escalate the vulnerability.
Flask - Read Secret Key
The main page of a Flask application will probably have the
global object where the secret is configured.app
Direct Access
If the vulnerability is in the main file:
app.secret_key
Cross-File Traversal
If the vulnerability is in a different Python file, use this gadget to traverse to the main module:
__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.secret_key
Use this payload to access
(the name in your app might be different) to be able to sign new and more privileged Flask cookies.app.secret_key
Werkzeug - Machine ID and Node UUID
Access the machine_id and uuid node, which are the main secrets you need to generate the Werkzeug pin for accessing the Python console in
/console if debug mode is enabled:
{ua.__class__.__init__.__globals__[t].sys.modules[werkzeug.debug]._machine_id} {ua.__class__.__init__.__globals__[t].sys.modules[werkzeug.debug].uuid._node}
Note: You can get the server's local path to
by generating an error in the web page which will reveal the path.app.py
If the vulnerability is in a different Python file, use the Flask traversal trick above to access objects from the main Python file.
Django - SECRET_KEY and Settings Module
The Django settings object is cached in
sys.modules once the application starts. With only read primitives you can leak the SECRET_KEY, database credentials, or signing salts:
When DJANGO_SETTINGS_MODULE is Set (Usual Case)
sys.modules[os.environ['DJANGO_SETTINGS_MODULE']].SECRET_KEY
Through the Global Settings Proxy
a = sys.modules['django.conf'].settings (a.SECRET_KEY, a.DATABASES, a.SIGNING_BACKEND)
Cross-Module Access
If the vulnerable gadget is in another module, walk globals first:
__init__.__globals__['sys'].modules['django.conf'].settings.SECRET_KEY
Once the key is known, you can forge Django signed cookies or tokens similar to Flask.
Environment Variables / Cloud Credentials
Many jails still import
os or sys somewhere. Abuse any reachable function __init__.__globals__ to pivot to the already-imported os module and dump environment variables containing API tokens, cloud keys, or flags:
Via Subclass Enumeration
# Classic os._wrap_close subclass index may change per version cls = [c for c in object.__subclasses__() if 'os._wrap_close' in str(c)][0] cls.__init__.__globals__['os'].environ['AWS_SECRET_ACCESS_KEY']
Via Loaders (If Subclass Index is Filtered)
__loader__.__init__.__globals__['sys'].modules['os'].environ['FLAG']
Environment variables are frequently the only secrets needed to move from read to full compromise (cloud IAM keys, database URLs, signing keys, etc.).
Django-Unicorn Class Pollution (CVE-2025-24370)
django-unicorn (<0.62.0) allowed class pollution via crafted component requests. Setting a property path such as __init__.__globals__ let an attacker reach the component module globals and any imported modules (e.g., settings, os, sys). From there you can leak SECRET_KEY, DATABASES, or service credentials without code execution.
The exploit chain is purely read-based and uses the same dunder-gadget patterns as above.
Gadget Chaining Patterns
Recent CTFs show reliable read chains built only with attribute access and subclass enumeration. Key patterns:
Basic Traversal
__init__.__globals__['module_name'].attribute
Via sys.modules
__init__.__globals__['sys'].modules['module_name'].attribute
Via Loaders
__loader__.__init__.__globals__['sys'].modules['module_name'].attribute
Via Subclass Enumeration
[c for c in object.__subclasses__() if 'target' in str(c)][0].__init__.__globals__['module'].attribute
Community Resources
Use pyjailbreaker - a community-maintained catalog of hundreds of minimal gadgets you can combine to traverse from objects to
__globals__, sys.modules, and finally sensitive data. Use it to quickly adapt when indices or class names differ between Python minor versions.
Quick Reference
| Target | Payload Pattern |
|---|---|
| Flask secret | |
| Django SECRET_KEY | |
| Environment vars | |
| Werkzeug debug | |
| Cross-file access | |