
42% of all committed code is now AI-generated (SonarSource State of Code 2026). Python is where most of that code lands. It's the default language for AI/ML, the backbone of data engineering, and the fastest-growing surface for web APIs. Every FastAPI endpoint, every Jupyter notebook that reaches production, every Django app with 200 dependencies, and now every AI coding assistant are all generating massive amounts of Python.
And often, that code has vulnerabilities. Endor and CMU Agent Security League found that 87% of AI agent-generated code contains at least one vulnerability and only 48% of developers say they always verify AI-generated code before committing it. Python vulns are only growing.
Python's dynamic typing and batteries-included standard library create recurring vulnerability classes that appear in virtually every production codebase:
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}"). The fix is parameterized queries, but Python's multiple database libraries (sqlite3, psycopg2, SQLAlchemy, Django ORM) each have different parameterization syntax.yaml.load() without SafeLoader, pickle.loads() on untrusted input, jsonpickle usage. Python's YAML library defaults to unsafe loading, making this a pervasive finding. The fix is always yaml.safe_load() or yaml.load(data, Loader=yaml.SafeLoader).requests.get() or urllib.request.urlopen(). Python's HTTP libraries accept any URL by default with no scheme or hostname validation.random.random() used for tokens, passwords, or session identifiers instead of secrets.token_hex() or secrets.token_urlsafe(). Python's random module explicitly states it's not suitable for security purposes, but the import is shorter.hashlib.md5() or hashlib.sha1() for password hashing instead of bcrypt or argon2. Also: hardcoded encryption keys, ECB mode usage, and insufficient key lengths.open(os.path.join(base_dir, user_input)) without sanitization. Python's os.path.join doesn't prevent directory traversal with ../ sequences.Dependency vulnerabilities. Python's ecosystem ships 400,000+ packages on PyPI. The average Python web app pulls 50-80 transitive dependencies. 77% of your code came from somewhere else, and much of it carries known CVEs. The average codebase now contains 581 vulnerabilities, up 107% year-over-year (Black Duck OSSRA 2026).
AI coding assistants are compounding the problem. Python code generated by AI contains 15-18% more security vulnerabilities than human-written Python (Opsera AI Coding Impact 2026), and AI-generated pull requests wait 4.6x longer for review. More code, more vulnerabilities, slower review.
Python's flexibility is also its remediation headache. The same vulnerability can appear in five different idioms:
# All of these are SQL injection — all need different fixescursor.execute("SELECT * FROM users WHERE id = %s" % user_id)cursor.execute("SELECT * FROM users WHERE id = {}".format(user_id))cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")cursor.execute("SELECT * FROM users WHERE id = " + user_id)session.execute(text("SELECT * FROM users WHERE id = " + user_id))
A human developer recognizes all five patterns instantly. A regex-based fixer catches some and breaks others. Structural remediation requires understanding Python's AST: how f-strings desugar, how SQLAlchemy's text() differs from raw cursor execution, and how Django's ORM parameterization works differently from psycopg2's.
Pixee's codemodder-python engine ships 60+ core codemods built on three complementary transformer strategies:
Concrete examples of what the codemods fix:
harden_pyyaml.py converts every yaml.load(data) to yaml.load(data, Loader=yaml.SafeLoader) across your codebase. Handles the six common call patterns including keyword arguments, variable assignment, and chained calls.
sql_parameterization.py detects string interpolation in cursor.execute() calls across sqlite3, psycopg2, mysql-connector, and SQLAlchemy. Converts to parameterized queries using each library's native syntax.
Before (CWE-89):
cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
After:
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
secure_random.py replaces random.random(), random.randint(), and random.choice() with secrets module equivalents in security-sensitive contexts. Uses dataflow analysis to distinguish security-sensitive from non-security usage (your random test data generator doesn't need secrets).
jwt_decode_verify.py ensures jwt.decode() calls include signature verification. PyJWT defaults changed between versions, making this a version-dependent vulnerability.
use_defused_xml.py replaces xml.etree.ElementTree, xml.sax, and xml.dom.minidom with defusedxml equivalents that prevent XXE attacks by default.
tempfile_mktemp.py replaces deprecated tempfile.mktemp() (race condition vulnerability) with tempfile.mkstemp() or tempfile.NamedTemporaryFile().
Each codemod is open-source. You can read the transformation logic, audit it, and verify it does what it claims before trusting it with your codebase.
Automated remediation is most effective when paired with automated triage. A typical Python project scan produces findings with a 71-88% false positive rate. Your team spends the same engineering hours investigating a false positive as remediating a real vulnerability.
Pixee's triage automation analyzes exploitability before generating fixes. A yaml.load() call in a test fixture that processes hardcoded YAML strings is technically a finding, but it's not exploitable. 95% false positive reduction means your team reviews fixes for the issues that actually matter.
The combined workflow: scan with your existing tools, triage with Pixee to eliminate noise, then auto-remediate the confirmed issues. The combined effect is typically a 91% reduction in security backlog.
Python's dependency vulnerabilities require a different remediation strategy than code-level findings. Bumping a package version can break APIs, remove features, or introduce incompatibilities that cascade through your dependency tree.
Pixee's SCA remediation approach goes beyond version bumps:
For these cases, human expertise is irreplaceable. Automated remediation handles the predictable 80% so your team has time for the 20% that requires judgment.
If your Python security backlog is growing faster than your team can address it, and AI-generated code is accelerating that growth, the starting point is separating signal from noise.
Pixee:
Pixee:
The briefing security leaders actually read. CVEs, tooling shifts, and remediation trends — distilled into 5 minutes every week.
Join security leaders who start their week with AppSec Weekly. Free, 5 minutes, no fluff.
First briefing drops this week. Check your inbox.
Weekly only. No spam. Unsubscribe anytime.