# Nine 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.

- URL: https://artcode.software/blog/2026-07-08-cwe-top-errors-ai-generated-code
- Author: Artur Kluz, Founder, AI architect (https://www.linkedin.com/in/arturkluz/)
- Published: 2026-07-08
- Updated: 2026-10-16
- Language: en
- Tags: security, cwe, ai-code-generation, engineering
- Publisher: ArtCode Software (https://artcode.software)

LLM-generated code has a recognisable fingerprint. After auditing code shipped between 2024 and 2026 that contained AI-generated functions, the same nine 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.

**In short.** Nine weaknesses keep recurring in code generated by language models, among them CWE-798 (hardcoded credentials), CWE-89 (SQL injection through string concatenation) and CWE-79 (XSS). The causes are the makeup of the training data and shortcuts taken from prompts. OWASP and CWE tests, linting in pre-commit and a thin, audited wrapper layer reduce them.

## 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 nine

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 ships this prevention harness alongside AI code generators at regulated Polish SaaS companies. 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 nine patterns is most exposed, the [AI Readiness Audit](/#zalacznik-1) includes a code-sample walkthrough against this list. If you want ongoing protection as the model and the codebase evolve, an AI architect can embed the prevention patterns into your development process. The scope is described in the [offer](/#oferta).
