The Threat Model Has Shifted
OWASP top-10 catalogs the canonical vulnerability classes in human-authored code: injection, broken authentication, sensitive data exposure, XML external entities, broken access control, security misconfiguration, XSS, insecure deserialization, components with known vulnerabilities, insufficient logging.
These remain real. AI-generated code can still produce SQL injection. But AI-generated code also produces a different distribution of vulnerabilities, patterns characteristic of how language models reason about code that show up rarely in human-authored code.
This post catalogs the patterns we have seen across hundreds of thousands of AI-generated PRs, and the scanning approaches that catch them.
Pattern 1: The Plausible-Looking Wrong Crypto
LLMs trained on a decade of code see a lot of crypto. They have absorbed which functions look reasonable. They will confidently write hashlib.md5(password).hexdigest() because that pattern shows up in tutorials, even though MD5 for passwords is wrong.
Why humans rarely write this: humans who know enough to call hashlib usually know enough to call bcrypt or argon2. The AI has the breadth without the calibration.
The scan: a per-language ban-list of cryptographic primitives in security-sensitive contexts. MD5 and SHA-1 for password hashing, ECB mode for symmetric encryption, hardcoded IVs, deterministic salts, missing padding. The list is small and well-known.
Pattern 2: The Confidently-Wrong Permission Check
The AI implements an authorization check that looks correct: it checks the user's role, it returns 403 on mismatch. The check is at the wrong layer (controller instead of service) or it checks the wrong attribute (the request's claimed user ID instead of the authenticated session's user ID).
Why humans miss this less: senior engineers have internalized the principle "trust the session, not the request." The AI sometimes does, sometimes does not, and there is no consistent signal in the local code that tells it which is right.
The scan: per-endpoint check that authorization runs against the authenticated identity, not against any attribute supplied in the request. Static analysis can catch many cases. Manual review of high-sensitivity endpoints catches the rest.
Pattern 3: The Leaked Secret In A Helpful Default
A new function with a defaulted argument: def send(email, api_key="sk_test_..."):. The AI saw the test key in some example and used it as a default. The default ships to production. It looks like a stub but actually authenticates.
Why humans rarely do this: humans who think about a key default at all tend to use None or raise an error. The AI sometimes uses an actual key it remembered, especially if the test key was in its training data.
The scan: regex sweep for common API key formats in default arguments and in committed code. The patterns are well-known (Stripe, AWS, GitHub, etc.). Block any match at PR time.
Pattern 4: The Disabled Security Check In A Helpful Refactor
The AI is refactoring a function. The original code had a check: if not is_admin(user): raise PermissionError. The AI's refactor moves the check, and it gets dropped in the move. The new code works correctly for happy-path users and silently bypasses the admin check.
Why humans miss this less: humans tend to preserve security checks when refactoring because they recognize their importance. The AI does not always recognize.
The scan: detect any diff that removes a call to a function named like is_admin, has_permission, check_access, require_role, authenticate. Removal must be explained. Block with annotation if no test covers the removed path.
Pattern 5: The Race Condition From "Cleaner" Code
The AI sees two-step code (if not exists: create) and "improves" it to a single line. The original two-step has a race condition the AI may or may not preserve, but more concerning: the AI's rewrite can introduce a new race the original did not have.
Why humans handle this better: humans rewriting concurrency code think about it. The AI applies pattern matching from non-concurrent contexts.
The scan: detect concurrency-sensitive primitives in the diff (locks, atomic operations, transaction boundaries). Any AI-generated change to these must include explicit reasoning in the PR description.
Pattern 6: The Logging Of Sensitive Data
The AI adds debug logs as part of a change. The logs include the request body, which includes the password the user is rotating. The log line is technically correct and helpful for debugging. It is also a serious compliance failure.
Why humans miss this less: humans who write security-sensitive code have absorbed "do not log secrets." The AI knows it but does not always apply it.
The scan: detect new logging statements that interpolate variables matching sensitive-data heuristics (variable names containing "password," "token," "key," "ssn," "credit_card," etc.). Block at PR time. The false positive rate is low.
Pattern 7: The CORS Wildcard As A Shortcut
The AI is implementing a new endpoint. CORS comes up. The AI sets Access-Control-Allow-Origin: * because it remembers that wildcard makes the development browser happy. The wildcard ships.
Why humans miss this less: humans setting CORS think about which origins. The AI sometimes does, sometimes does not.
The scan: detect any new CORS configuration in the diff. Block if origin is wildcard. The team can override with a justification.
Pattern 8: The Disabled TLS Verification
The AI is making an outbound HTTP call. It hits a TLS error in the local dev environment. It adds verify=False and the call works. The code ships.
Why humans miss this less: humans who add verify=False know it is a hack. They mark it. The AI may not recognize the implication.
The scan: detect verify=False, InsecureRequestWarning suppression, rejectUnauthorized: false, or equivalents. Block at PR time. Override requires a comment explaining why.
What These Have In Common
Three properties of AI-characteristic vulnerabilities:
- They look reasonable. The vulnerable code reads as competent.
- They come from pattern-matching on training data without the contextual judgment that humans bring.
- They are detectable by narrow, specific scans. A pattern-matching approach catches them at high precision.
The Scanning Layer
We run the AI-specific scans alongside conventional SAST and dependency scans. The conventional scans catch the OWASP-class issues. The AI-specific scans catch the AI-characteristic issues. Both run on every PR before human review. See AI SAST scanning inside pull requests.
The false positive rate of the AI-specific scans is meaningfully lower than conventional SAST because the patterns are narrower. Most teams accept all the AI-specific findings as actionable.
What This Means For Security Teams
Three implications:
Update the threat model. The AI-characteristic patterns above are not in your security training curriculum from 2018. Add them.
Update the SAST rules. Most commercial SAST tools have not adapted to AI-generated code patterns. The team's own SAST should have rules for the patterns we listed.
Update the review checklist. Reviewers should know to look for the AI-characteristic patterns specifically when reviewing AI PRs. Not all reviewers know yet.
Looking Ahead
The patterns above are current. New ones will appear as models change. The discipline is to keep monitoring escaped vulnerabilities for AI-characteristic patterns and to write rules as they emerge. Treat the rule set as a living artifact, the same way the team treats its incident-derived guardrails. See postmortem-to-prompt pipeline.
For the broader security architecture, see enterprise safety layers and CVE patching at scale.
Frequently asked questions
Is AI-generated code secure?
It can be, but AI-generated code carries a characteristic set of vulnerabilities distinct from human-authored code. Because the model pattern-matches on training data without a senior engineer's contextual judgment, it will confidently write plausible-but-wrong crypto, request-trusting authorization checks, leaked secrets in default arguments, and CORS or TLS shortcuts. These are detectable by narrow, high-precision scans run on every PR before human review. See enterprise safety for AI-generated code for the full architecture.
What security vulnerabilities are common in AI-generated code?
Eight recurring patterns: weak cryptographic primitives (MD5/SHA-1 for passwords), permission checks against the request instead of the authenticated session, secrets in defaulted function arguments, security checks dropped during refactors, races introduced by 'cleaner' rewrites, sensitive data logged in debug statements, wildcard CORS origins, and disabled TLS verification. They share three traits, they look reasonable, they stem from training-data pattern-matching, and each is catchable by a targeted scan.
Does OWASP top-10 cover AI-generated code?
Only partially. OWASP top-10 catalogs the canonical vulnerability classes in human-authored code (injection, broken access control, XSS and the rest), and those remain real for AI too. But AI produces an additional distribution of characteristic vulnerabilities that a 2018-era security curriculum won't flag. Security teams should update the threat model, add rules to their SAST, and extend the reviewer checklist specifically for AI PRs.
How do you scan AI-generated code for security issues?
Run AI-specific scans alongside conventional SAST and dependency scans on every PR before human review. Conventional tools catch the OWASP-class issues; the AI-specific scans use narrow rules (banned crypto primitives, API-key format regexes, removal of authorization calls, verify=False detection), to catch the AI-characteristic patterns. Because those rules are tight, their false-positive rate is lower than general SAST, and most teams accept the findings as actionable. See AI SAST scanning inside pull requests.
Why does AI write insecure cryptography?
Language models trained on a decade of code have absorbed which crypto functions look reasonable without the calibration to know which are wrong, so they'll confidently write MD5 password hashing because that pattern appears in tutorials. Humans who know enough to call a hashing library usually know enough to reach for bcrypt or argon2; the AI has the breadth without the judgment. The defense is a per-language ban-list of insecure primitives in security-sensitive contexts, which is small and well-known.
EnsureFix Compliance Team
The EnsureFix compliance team maps the platform's safety layers and audit trails to SOC 2, HIPAA, and PCI requirements, and advises regulated-industry customers on secure rollout.