AI agents write code fast, and that's exactly why you need to review AI-generated code more carefully now. Generated code is usually clean, well named and confident, which makes it easy to approve without really reading it. GitHub's own documentation for its coding agent says plainly that agents "can produce incorrect or suboptimal code, including code that contains security vulnerabilities," and that session logs "do not replace your own review and testing" (GitHub Docs).
You don't need to be a senior engineer to review well. You need a routine that puts the riskiest things first. Here's ours.
Step 0: make the diff reviewable
Most bad reviews start with a diff that's too big to review. Before you read any code:
- Ask for small changes. One feature or one fix per branch. If the agent touched 40 files for a button, ask it to split the work into smaller pull requests. Cursor even has a built-in
/split-to-prsskill for this (Cursor docs). - Ask for a summary of intent. "List every file you changed and why, in one line each." Then compare the list with what you asked for. Changes you didn't request are your first red flag.
- Ask for evidence. The build output, the test results and the lint results, pasted into the conversation, not just "tests pass."
Step 1: access control first
Broken Access Control is #1 on the OWASP Top 10:2025. OWASP reports that "100% of the applications tested were found to have some form of broken access control" (A01:2025). For most vibe-coded apps, this is the bug that matters most.
For every new route, server action or query, ask one question: can user A read or change user B's data?
If you're on Supabase, check the database layer as well:
- Every table in an exposed schema has RLS enabled. Supabase warns that a table without it "is readable and writable by any role with a grant on it," and that adding policies doesn't revoke existing grants (Supabase RLS).
- Policies name a role (
to authenticated) and use(select auth.uid()). - Update policies have
with check. Without it, a user may be able to reassign a row to someone else. - Watch out for views. By default, views bypass RLS. On Postgres 15 and above, create them
with (security_invoker = true). - Don't base policies on
user_metadata. Users can edit it themselves.
The fastest way to verify is to make the agent prove it. Ask it to write a test where a second user tries to read, update and delete the first user's records, and to show that the test fails before the fix and passes after. Our Supabase RLS audit skill gives your agent a checklist for the database side.
Step 2: secrets and the browser boundary
AI-written code often blurs the line between server and client. Check these:
- No
NEXT_PUBLIC_on anything secret. Next.js inlines these values into the JavaScript bundle sent to the browser at build time (Next.js docs). - No Supabase secret key (or legacy
service_rolekey) in client code. It "bypasses every Row Level Security policy you have" (Supabase API keys). The publishable key is the only one meant for the browser. - No hardcoded credentials, even in tests or seed scripts. Search the diff for
key,secret,token,passwordandBearer. - Turn on secret scanning. GitHub runs it automatically and for free on public repositories. For organization-owned private repos, it's available with GitHub Secret Protection on GitHub Team or Enterprise Cloud. If something does leak, rotate the credential right away. GitHub notes that removing it from Git history is "time-intensive and often unnecessary if you've already revoked the credential" (GitHub secret scanning).
Step 3: every new dependency
Software Supply Chain Failures sits at #3 in the OWASP 2025 list. It expands 2021's "Vulnerable and Outdated Components" to cover the whole dependency and build ecosystem (OWASP). AI adds a twist: package hallucinations, where the model recommends a package that doesn't exist. Attackers can register those names and publish malicious code under them.
In a peer-reviewed study presented at USENIX Security 2025, researchers generated 576,000 code samples with 16 LLMs. They found an average hallucinated-package rate of at least 5.2% for commercial models and 21.7% for open-source models, with 205,474 unique made-up package names (Spracklen et al., USENIX Security 2025).
So for every line added to package.json or requirements.txt:
- Does the package exist on the official registry, and is it the one you meant (check for near-miss spellings)?
- Is it maintained, and is it widely used?
- Do you actually need it, or would a few lines of code do the job?
Step 4: input, output and errors
- User input that reaches SQL, HTML, redirects, file paths or shell commands should be validated or parameterized. Injection is still on the OWASP list, at #5.
- Error handling. "Mishandling of Exceptional Conditions" is new at #10 (OWASP). Look for empty
catchblocks, errors that are swallowed and then reported as success, and stack traces shown to users. - Logging. Make sure failures are logged somewhere you'll actually see them, and that the logs contain no secrets or personal data.
Step 5: does it do what you asked?
Security review isn't the whole job. Read the code against your acceptance criteria:
- Does it handle empty states, missing records and slow networks?
- Did the agent "fix" a failing test by weakening the assertion?
- Did it add a TODO, a stub or a mock in production code to get things working?
- Is there a simpler version? AI code tends to over-abstract.
Use agents to review agents (but not instead of you)
The major tools ship review features you can run before your own pass:
- Claude Code has a bundled
/code-reviewskill (Claude Code docs). - Cursor has built-in
/review,/review-bugbotand/review-securityskills (Cursor docs). - Codex CLI has
/review, which reports prioritized findings "without modifying your working tree" (Codex CLI). - GitHub Copilot code review can review pull requests and suggest fixes (GitHub Docs).
Two habits make AI review more useful. First, run it in a fresh session, or with a different tool or model than the one that wrote the code, so the reviewer doesn't share the author's assumptions. Second, give it a specific checklist (Steps 1–4 above) instead of "review this."
Treat AI findings as leads, not verdicts. Confirm each one, and remember that "no issues found" doesn't mean the code is safe.
How to review AI-generated code: the one-screen checklist
[ ] Diff is small and every changed file is expected
[ ] Build, tests, lint pass (output pasted, not claimed)
[ ] User A cannot read/change user B's data (tested)
[ ] RLS on every exposed table; update policies have WITH CHECK
[ ] No secrets in code; nothing secret has a NEXT_PUBLIC_ prefix
[ ] Every new dependency exists, is intended, and is needed
[ ] Input validated/parameterized; errors not swallowed
[ ] Acceptance criteria met; no weakened tests or leftover stubs
[ ] AI review run in a fresh session; findings verified by a human
Save it as an agent skill and you can run it on every branch. Our code review skill does exactly that, and our vibe coding security checklist turns Steps 1 to 4 into a 30-minute pre-launch pass.
Keep reading
- How to run coding agents safely: permissions, sandboxes and secrets
- How to vibe code a SaaS with Supabase and Vercel in a weekend
- Git and GitHub basics for vibe coders
FAQ
Is AI-generated code safe to deploy without review?
No. GitHub documentation says coding agents can produce code that contains security vulnerabilities and that session logs do not replace your own review and testing.
What should I check first in AI-written code?
Check access control first. Ask whether user A can read or change user B data, and on Supabase confirm every exposed table has Row Level Security enabled.
What is a hallucinated package?
A hallucinated package is a dependency an AI model recommends that does not exist. Attackers can register those names, so confirm every new package on the official registry.
Can an AI agent review its own code?
It can help, but run the review in a fresh session or with a different tool, give it a specific checklist, and treat its findings as leads that a human confirms.
