Skip to content

Add Python script static analysis handler#28

Merged
ldayton merged 4 commits intomainfrom
add-python-static-analysis
Jan 14, 2026
Merged

Add Python script static analysis handler#28
ldayton merged 4 commits intomainfrom
add-python-static-analysis

Conversation

@ldayton
Copy link
Owner

@ldayton ldayton commented Jan 13, 2026

Summary

Adds a handler that auto-approves safe Python scripts by statically analyzing their AST. Uses a strict whitelist approach.

Threat Model

This is NOT a sandbox. We're protecting against AI coding assistants (Claude Code) accidentally running dangerous scripts, not against adversarial or malicious code.

Key insight: An AI won't deliberately craft tokenize.open() bypasses or ().__class__.__bases__[0].__subclasses__() exploits. It will accidentally reach for os.system(), subprocess.run(), or open("file.txt", "w").

What gets auto-approved

python --version              # Version/help flags
python -m json.tool           # Safe stdlib modules
python safe_script.py         # Scripts that pass analysis

Safe modules (pure computation, no I/O):
json, re, math, collections, itertools, functools, hashlib, datetime, dataclasses, typing, ast, zlib, etc.

What requires confirmation

python                        # Interactive mode
python -c 'code'              # Inline code
python -m http.server         # Arbitrary modules
python script_with_os.py      # Dangerous imports

Blocked modules (likely AI mistakes):

Module Risk
os, subprocess, shutil System execution
pathlib, io, open() File I/O
socket, http, urllib Network
gzip, bz2, lzma Hidden file I/O via .open()
codecs Hidden file I/O via .open()
inspect File reading via getsource()

Blocked builtins: eval, exec, open, __import__, globals, getattr

Conservative defaults

  • Unknown imports → ask (third-party packages like pandas, requests)
  • Large files (>100KB) → ask
  • Syntax errors → ask
  • Non-.py files → ask

Test plan

  • 67 tests covering safe scripts, dangerous scripts, bypass attempts
  • just check passes on Python 3.11-3.14

Adds a handler that can auto-approve safe Python scripts by analyzing
their AST. Uses a whitelist approach: only scripts using known-safe
modules and builtins are approved.

Threat model: This protects against AI coding assistants accidentally
running dangerous scripts, NOT against adversarial/malicious code.
An AI won't deliberately craft bypass code - it might just accidentally
use os.system() or open() for file writes.

Auto-approved:
- python --version, --help
- python -m json.tool, calendar, pydoc
- Scripts using only safe modules (json, re, math, collections, etc.)

Requires confirmation:
- python -c (inline code)
- python -m <arbitrary module>
- Scripts importing os, subprocess, pathlib, socket, etc.
- Scripts using eval, exec, open, __import__

Blocked modules include those with hidden file I/O capabilities:
- gzip, bz2, lzma (have .open() methods)
- codecs (codecs.open())
- inspect (getsource reads files)
@ldayton ldayton marked this pull request as ready for review January 13, 2026 19:05
Add coverage for:
- Legacy process modules (popen2, commands)
- XML parsing (XXE vulnerabilities)
- Additional deserialization (dill, marshal, jsonpickle)
- Archive extraction (tarfile, zipfile)
- CGI/httpoxy vulnerabilities
- Frame/traceback introspection attributes
- Full set of os.spawn*/exec* variants
- Subprocess method names
New test classes:
- TestDangerousModulesBandit: marshal, dill, jsonpickle, configparser
- TestDangerousModulesXML: xml.etree, xml.sax, xml.dom, xml.parsers
- TestDangerousModulesArchive: tarfile, zipfile
- TestDangerousModulesCGI: cgi, cgitb, wsgiref.handlers
- TestDangerousModulesLegacy: commands, popen2
- TestDangerousAttributes: subprocess methods, os.spawn/exec variants
- TestDangerousReflection: frame/generator/code introspection
- TestDangerousFileOps: file read/write methods, pathlib methods
- TestNetworkOps: socket, urllib, http, ftp, telnet, xmlrpc
- TestUnitAnalysisExtended: direct analyzer tests

Also fixes detection of non-dunder reflection attributes (gi_frame,
f_globals, etc.) by adding REFLECTION_ATTRS set to SafetyAnalyzer.
Only calendar is truly inert (just prints output). The others:
- timeit: executes its statement argument as code
- json.tool: reads files passed as arguments
- pydoc: imports modules, executing their top-level code
@ldayton ldayton merged commit 8dc12d6 into main Jan 14, 2026
1 check passed
@ldayton ldayton deleted the add-python-static-analysis branch January 14, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant