AI coding assistants have made it trivially easy to go from idea to working prototype in minutes. That speed is genuinely useful. The danger is treating a prototype as production-ready just because it compiles and the happy path works. AI-generated code carries its own class of risks: plausible-looking logic with subtle bugs, outdated patterns copied from training data, missing error handling, and security holes that only show up under adversarial conditions.

This guide is a structured checklist for the review pass that should happen before any AI-generated code ships. It assumes you are a developer who can read and reason about code, even if you did not write the specific snippet in question.

Understand What You Are Reviewing

Before running any tools, read the code with fresh eyes and answer these questions:

  • What does this code actually do? Not what you asked for. What does it do? Trace the data flow from input to output.
  • What does it assume? Look for implicit assumptions about input shape, authentication state, environment variables, and external service availability.
  • What does it trust? Any value that crosses a trust boundary (user input, API response, file content, environment variable) is a potential attack surface.

AI models are good at producing code that satisfies the literal request. They are less reliable about encoding the unstated constraints that experienced engineers carry in their heads. Your job in this first pass is to surface those gaps.

Dependency Hygiene

AI models suggest packages based on training data that has a cutoff date. That means you may receive recommendations for libraries that have since been deprecated, superseded, or found to contain vulnerabilities.

  • Run npm audit, pip-audit, or the equivalent for your ecosystem on every dependency the model introduced.
  • Check that each package is actively maintained. Look at the repository: recent commits, open issues, and a published security policy are good signs.
  • Prefer well-known, minimal dependencies over unfamiliar convenience packages. If a model suggests a package you have never heard of, verify it is the real thing and not a typosquatted name.
  • Pin versions in production. Floating ranges like ^1.2.0 can silently pull in a breaking or malicious patch release.

Input Validation and Sanitization

This is the most common place AI-generated code falls short. Models tend to write the happy path. Adversarial inputs are an afterthought.

  • Validate at the boundary. Every function that accepts external data should validate type, shape, length, and allowed values before doing anything with that data.
  • Never trust user-controlled values in dynamic queries. SQL injection, NoSQL injection, and template injection are all still live threats. Use parameterized queries or an ORM that handles escaping, not string concatenation.
  • Sanitize before rendering. If the output goes into HTML, a shell command, a file path, or an OS call, apply the appropriate escaping library for that context.
  • Check for path traversal. Any code that builds a file path from user input should canonicalize the path and verify it stays inside the intended directory.

Authentication and Authorization

Prototype code often skips auth entirely or implements it incorrectly. Look for these specific issues:

  • Missing authorization checks. A route may correctly verify that a user is logged in but fail to verify that the logged-in user is allowed to access the specific resource they requested. This is broken object-level authorization, one of the most common API vulnerabilities.
  • Secrets in code. AI models sometimes hard-code placeholder credentials or, worse, echo back secrets that appeared in your prompt. Audit every string literal. Use environment variables or a secrets manager instead.
  • Weak token handling. Check that JWTs are verified with a strong algorithm, that session tokens are invalidated on logout, and that tokens have appropriate expiry times.
  • CORS misconfiguration. A wildcard Access-Control-Allow-Origin: * on an authenticated endpoint is a real vulnerability. Tighten it to the specific origins you control.

Error Handling and Information Disclosure

AI-generated code frequently propagates raw exceptions to the caller, which leaks stack traces, internal paths, and library versions to anyone who can trigger an error.

  • Catch exceptions at the boundary and return sanitized, generic error messages to clients. Log the full detail server-side where only you can see it.
  • Avoid returning different error messages for conditions like “user not found” versus “wrong password.” Distinct messages allow user enumeration attacks.
  • Check that logging statements do not capture sensitive data like passwords, tokens, or personally identifiable information.

Use Static Analysis and Linting

Manual review catches logical issues. Automated tools catch consistent mechanical ones. Run both.

  • For Python: bandit for security-specific patterns, ruff or flake8 for general quality, and a type checker like mypy or pyright.
  • For TypeScript and JavaScript: eslint with a security plugin, and run the TypeScript compiler in strict mode. AI-generated TypeScript often uses any to paper over type mismatches, which defeats the purpose of the type system.
  • For any language, consider a SAST (static application security testing) tool. Many are available as free tiers or open-source projects, and they flag patterns like hardcoded secrets, unsafe deserialization, and known-bad cryptographic primitives.

Write Tests That Attack the Code, Not Just Confirm It

AI models often generate tests alongside code. Those tests are usually optimistic: they verify that the happy path returns the expected result. That is not a security test suite.

  • Write tests that pass boundary values: empty strings, null, very large numbers, negative numbers, Unicode edge cases.
  • Test rejection cases. If a function should reject unauthenticated calls, write a test that verifies the rejection, not just that authenticated calls succeed.
  • For functions that handle user input, write tests that pass payloads commonly used in injection attacks and verify they are rejected or sanitized correctly.
  • Test error paths explicitly. Call the function in ways that should trigger exceptions and assert that the error response is safe and informative without being too revealing.

Use the Model to Help You Review Its Own Output

There is a practical trick that often surfaces real issues: feed the AI-generated code back to a capable model and ask it to act as an adversarial reviewer. Models like Claude Fable 5 (claude-fable-5) or Claude Sonnet 4.6 (claude-sonnet-4-6), which support adaptive thinking, are particularly good at this kind of systematic reasoning over large code surfaces. Both offer a 1M-token context window, which means you can include a substantial codebase in a single review pass.

A prompt pattern that works well:

You are a security engineer doing a pre-ship audit. Review the following code for:
- Input validation gaps
- Authorization flaws
- Sensitive data exposure
- Dependency risks
- Error handling that leaks internals

Be specific. Cite the exact line or function where each issue occurs.

[paste code here]

Do not treat the model’s output as a definitive audit. Treat it as a second set of eyes that is fast and thorough about common patterns. You still need to reason about the findings and verify them yourself.

When using adaptive thinking via the Anthropic SDK, you can enable it like this in Python:

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-fable-5",
    max_tokens=8096,
    thinking={"type": "adaptive"},
    messages=[
        {
            "role": "user",
            "content": "Review this code for security issues: ..."
        }
    ]
)

Checklist Before You Merge

  1. Read the code end-to-end and understand the data flow.
  2. Audit every new dependency with your ecosystem’s audit tooling.
  3. Confirm all external inputs are validated and sanitized.
  4. Verify authentication and per-resource authorization on every endpoint.
  5. Search for hard-coded secrets and replace them with environment variables.
  6. Confirm errors are caught and return sanitized messages to callers.
  7. Run a SAST tool and address flagged findings.
  8. Write adversarial tests covering boundary values, rejection cases, and error paths.
  9. Run an AI-assisted review pass and triage the output.
  10. Get a second human review for any code touching authentication, payments, or sensitive data.

Takeaway

AI-generated code is a starting point, not a finished product. The speed advantage is real, but only if you spend the time you saved on a disciplined review rather than skipping it entirely. The checklist above is not exhaustive, and every codebase has domain-specific risks worth adding to it. Build the habit of running through these steps before every merge, and the prototypes you ship will actually deserve to be called software.