Ten flaws AI writes into your code
Hardcoded secrets, SQL injection, path traversal, weak crypto. The CWEs that recur in AI-generated code, with a prevention pattern for each.
LLM-generated code has a recognisable fingerprint. After auditing around fifty codebases shipped between 2024 and 2026 that contained AI-generated functions, the same ten weaknesses appear in roughly the same order.
This post lists them in approximate frequency, explains what makes model-generated code vulnerable, and gives one concrete prevention pattern for each.
The list is not the OWASP Top 10. It is a focused subset for the code a regulated SME ships into production: web APIs, internal services, data pipelines, integrations.
1. CWE-798 - Hardcoded credentials in source code
The most frequent by a margin. Models trained on public GitHub data have seen thousands of repositories where API keys, database URIs, and JWT secrets are committed once and removed in a panic. They reproduce the pattern in generated code with the same human plausibility. Common symptoms: API_KEY = "sk-..." literals, .env-style blocks inlined into Python or JavaScript, connection strings with credentials inline.
Prevention: treat every credential as a runtime-injected value from environment variables or a secret manager (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault). A pre-commit hook with gitleaks or trufflehog blocks accidental commits; a CI step fails the build on secrets in the diff.
2. CWE-89 - SQL injection via string concatenation
Models default to string-built queries when prompted for "a function that filters users by email." The pattern f"SELECT * FROM users WHERE email = '{email}'" appears at a frequency that suggests the training data has it in healthy supply. Also prone to building dynamic ORDER BY or column whitelists from user input without parameterisation.
Prevention: use parameterised queries exclusively. In Python, cursor.execute("SELECT ... WHERE email = %s", (email,)) with psycopg. In JavaScript, prepared statements via pg, mysql2, or an ORM. python-bandit and eslint-plugin-security catch concatenation patterns; an SQL injection test set runs in CI against every endpoint.
3. CWE-79 - Cross-site scripting via unescaped rendering
For React and Vue this often means dangerouslySetInnerHTML and v-html directives applied to user input or to model-generated strings that include user data. For server-rendered Jinja2 or Django templates, missing |safe discipline. The pattern is harder to detect at code review than SQL injection because the vulnerability lives in the data path, not the control flow.
Prevention: default to safe rendering. Treat any string that crosses a trust boundary as text, not as HTML. Sanitise at the boundary using DOMPurify (browser) or bleach (Python). If the product genuinely renders HTML from a controlled source, isolate that path behind an explicit allow-list and audit it in the next security review.
4. CWE-22 - Path traversal via unsanitised file paths
Models reading or writing files by user-supplied names without checking for ../ sequences or absolute paths is recurring. Common in document upload pipelines, image processors, and CSV importers. The model often catches obvious .. cases but misses Unicode normalisation or symlink targets.
Prevention: resolve the user-supplied path with the OS canonicalisation, then verify the resolved path is inside an allowed root. In Python, os.path.realpath followed by a prefix check. In Go, filepath.Clean and the same prefix check. Never concatenate user input into a path fed to open() without going through the resolver.
5. CWE-327 - Use of broken or risky cryptographic algorithm
Models frequently default to md5 for "a quick hash" or to DES, RC4, or ECB-mode AES for "an encryption function," both bad defaults the model treats as canonical. A subtler variant is crypto.createCipher (Node) or Random (Java) without a strong seed, or random instead of secrets in Python cryptographic contexts.
Prevention: restrict the cryptographic surface in your standard library wrappers. Force AES-GCM, ChaCha20-Poly1305, SHA-256 or SHA-3. Pin the algorithm at the import boundary so a weak primitive cannot be picked up by accident. A linter rule flags MD5, SHA-1, DES, RC4 outside of legacy tests.
6. CWE-94 - Code injection via dynamic evaluation
eval(), exec(), Function() constructors, and template engines that re-compile user input. Models writing helper functions in notebooks regularly include eval(input_data). Risk surface is small but high-impact: a single eval in a request handler exposed to user input is a remote code execution.
Prevention: no eval in shipped code. For dynamic templates, use a logic-less engine (Handlebars, Liquid with strict mode) and a permitted helper set. A pre-commit hook greps for eval(, exec(, Function(\" and breaks the build.
7. CWE-502 - Deserialisation of untrusted data
pickle.loads, yaml.load (without Loader=SafeLoader), Java ObjectInputStream, PHP unserialize on user input. Models trained on data science notebooks are heavy emitters of pickle.loads.
Prevention: YAML uses yaml.safe_load. Pickle is replaced by a JSON or Parquet round-trip. Java uses a documented allow-list of classes with ObjectInputStream filtering. PHP serialisation is replaced by json_encode/json_decode. For inter-service communication, use a typed schema (Protobuf, FlatBuffers, Avro) instead of native serialisation.
8. CWE-918 - Server-side request forgery
Models building "an image proxy" or "a webhook validator" often forward the request without restricting the destination URL. A request to https://your-service/image?url=https://attacker.internal becomes a foothold into the cloud metadata endpoint.
Prevention: allow-list of hostnames, not URL parsing tricks. Resolve the hostname, check the IP against private ranges (10.0.0.0/8, 169.254.0.0/16, etc.), and refuse if the resolved address is not on the allow-list. Run the proxy as a separate network identity with no access to internal services.
9. CWE-287 - Improper authentication
The broadest CWE in the list, with many forms in AI-generated code: missing token verification on protected endpoints, JWT validation that does not check the signature, session cookies set without Secure and HttpOnly, OAuth flows that skip the state parameter. A typical variant is a model writing if user.get("role") == "admin": directly on request data, with the role sourced from the JWT payload but never verified.
Prevention: centralise authentication. One middleware, one library, one place to audit. Models do not generate authentication code; they call a function in your auth layer. The function is tested, reviewed, and on the audit trail. Decentralised auth is the root cause of most CWE-287 in this list.
Why these recur in AI-generated code
Three factors stack. Training data composition. The corpus over-represents tutorial code, which is permissive by design (works on the developer's laptop, not in a production threat model). It also represents production code that has historic vulnerabilities. The model learns the surface pattern, not the threat model. Prompt-induced shortcuts. When the prompt is "write a Flask endpoint that returns the user profile," the model skips ahead to the happy path. Authentication, rate limiting, and error logging are absent unless the prompt names them. A developer who treats the output as a starting draft will catch this; one who treats it as finished code will not. Lack of context. The model does not know which fields are PII in your domain, which endpoints are admin-only, which integrations are reachable from the public internet. Asking the right questions is the engineering task; the model cannot ask them for you.
The prevention patterns that cut across all ten
Three engineering controls reduce the surface area for every CWE on this list. A test harness for the OWASP Top 10 and CWE Top 25 with the fixtures in OWASP Benchmark and NIST SARD. A linting and pre-commit stack (Bandit, ESLint with eslint-plugin-security, Gosec, Semgrep) that catches the obvious patterns. An architectural boundary where generated code calls into a thin, audited wrapper layer for credentials, file system, network, and database access.
How this connects to AI Act compliance
The AI Act Article 15 (accuracy, robustness, cybersecurity) bites hardest on this list. If your AI assistant generates code in a regulated pipeline, the output is part of the AI system. The output's security properties are the system's security properties. A documented prevention programme for the CWEs above is part of the conformity assessment under Article 43.
ArtCode Software has shipped this prevention harness alongside AI code generators at three regulated Polish SaaS companies in 2025-2026. The harness lives in the repo, runs in CI, and is referenced from the model card. If you need a review of where AI-generated code is currently in your pipeline and which of these ten patterns is most exposed, the AI Readiness Audit includes a code-sample walkthrough against this list. If you want ongoing protection as the model and the codebase evolve, the Fractional AI Architect Retainer embeds the prevention patterns into your development process.