Scout dangerous paths in Python modules — safely.
A Python module graph explorer that reveals hidden routes to sensitive modules, callables, and builtins.
ModScout recursively walks a module’s attributes (via dir()) to reveal potentially dangerous or interesting connections—like how random might indirectly reach os.system. It’s a safe, standalone tool for security auditing, dynamic analysis, and curiosity-driven inspection.
Think of it as a metal detector for Python’s module graph.
- 🚦 Safe-first traversal: reads only from
__dict__by default - 🧠 Smart matching: categories (
system,builtin,dangerous) + regex + explicit names - ⚙️ Fully configurable: JSON-driven rules and scan parameters
- 🧾 Readable output: console summary + structured JSON report
- 🧰 No dependencies: uses only the Python standard library
- Python 3.8+ (3.11+ recommended)
- No installation needed
# Show help
python ModScout.py -h
# Generate an example config
python ModScout.py --write-example
# Run using the default example config
python ModScout.py -c modscan.example.json
# Or run ad-hoc without config file
python ModScout.py --roots random --targets system,builtin --max-depth 3💡 On Windows, use
py -3.11 ModScout.pyif needed.
.
├─ ModScout.py # main analyzer (single file, no dependencies)
├─ modscan.example.json # safe starter config
├─ dangerous.json # broad config for high-risk discovery
├─ dangerous_report.json # example output from a scan
├─ cpython.json # optional: scan config for CPython internals
├─ Demo.png # sample run screenshot (as shown above)
├─ logo.png # pixel-style ModScout logo
├─ LICENSE # MIT
├─ .gitignore
└─ README.md
ModScout uses JSON configs. Key sections:
roots: root modules to start traversal fromrules: matching criteria (category, regex, names, etc.)categories: custom lists of modules/callables grouped by themescan: traversal settings (depth, risk, pruning)output: report configuration
{
"roots": ["random"],
"rules": [
{ "type": "category", "category": "system" },
{ "type": "category", "category": "builtin" }
],
"categories": {
"system": {
"modules": ["os", "subprocess", "ctypes", "socket", "ssl", "shutil"],
"callables": ["system", "run", "Popen", "fork"]
}
},
"scan": {
"max_depth": 4,
"max_objects": 60000,
"risk_getattr": false,
"prune_dunders": true
},
"output": {
"json_path": "modscan_report.json",
"limit": 2000
}
}A “maximal paranoia” config—enumerates filesystem, subprocess, import, and network modules/functions.
{
"roots": ["random"],
"rules": [
{ "type": "category", "category": "dangerous" },
{ "type": "qualname_regex", "pattern": "(^|\\.)builtins\\.(eval|exec|compile|open|__import__|input)$" }
],
"categories": {
"dangerous": {
"modules": ["os", "sys", "subprocess", "ctypes", "socket", "ssl", "importlib"],
"callables": ["system", "run", "exec", "eval", "open", "__import__"]
}
},
"scan": {
"max_depth": 6,
"max_objects": 120000,
"risk_getattr": false
},
"output": {
"json_path": "dangerous_report.json",
"limit": 10000
}
}Each run prints a console summary and writes a JSON report:
Example Output (CLI):
=== Summary ===
Roots: random
25 category:system
5 category:builtin
=== First 30 findings ===
[d=1] random._os :: module (os) -- category:system
[d=2] random._os.system :: function (os.system) -- category:system
[d=2] random._os.remove :: builtin_function_or_method (nt.remove) -- category:system
...
Saved JSON report to modscan_report.json (items written: 30/30)
Report fields:
path: full dotted path (e.g.,random._os.system)depth: how deep it was foundobject: type, module, qualname, originmatch: which rule triggered and why
- 🧱 Default traversal only inspects existing attributes; no arbitrary code runs.
⚠️ Enabling--risk-getattrmay trigger imports or property code—sandbox before use.- 🐢 Deep scans of large frameworks (
torch,tensorflow) may take time—exclude them viaexclude_module_prefixes.
The
DeprecationWarningseen in some environments (datetime.utcnow()) is harmless and will be addressed with a timezone‑aware patch.
-c, --config PATH Use a JSON config file
--roots r1,r2 Comma-separated roots (overrides config)
--targets t1,t2 Add quick category rules (e.g., system,builtin)
--max-depth N Set recursion depth
--risk-getattr Use getattr() if __dict__ missing (unsafe)
--json-out PATH Output JSON report file path
--limit N Limit findings in JSON (0 = no limit)
--write-example Generate modscan.example.json and exit
- Find a specific object:
{ "type": "qualname", "pattern": "random._os.system" } - Match any callable name:
{ "type": "callable_name", "pattern": "open" } - Create your own category (e.g., networking):
{ "modules": ["socket", "ssl"], "callables": ["create_connection"] }
Pull requests are welcome!
MIT License — see LICENSE.