AI-generated code is not automatically insecure — but it's not automatically safe either
It's tempting to have a strong opinion either way — that AI-written code is riskier, or that it's fine because "the model knows best practices." Neither framing is that useful in practice. The model can absolutely produce secure, well-structured code when asked clearly, and it can just as easily produce something that works perfectly in your test but has an obvious hole, because it optimized for the behavior you described, not the security properties you didn't mention.
The practical takeaway is the same one that applies to code from any source: review it, and build a checklist so you're not relying on memory to catch the important things.
Secrets and credentials
API keys, database credentials and tokens should never end up in code that ships to the browser, gets committed to a public repository, or appears in a client-side environment variable. AI tools will sometimes reach for the fastest way to make something work, which can mean hardcoding a key directly into a file if you don't explicitly direct it toward environment variables and server-side handling instead. Always check where a generated integration is actually reading its credentials from.
Dependencies you didn't personally choose
An agent that can install packages on your behalf is convenient, and it also means a dependency can enter your project without you deliberately vetting it. Periodically review what's actually in your dependency list, keep it as small as reasonably possible, and don't assume a package is trustworthy just because the AI suggested it — the same judgment you'd apply to a package a colleague proposed applies here.
Input validation and injection risks
Any data coming from a user — a form field, a URL parameter, an uploaded file — needs to be validated and treated as untrusted before it touches a database query, a shell command, or gets rendered back into a page. Ask explicitly for input validation and for protection against injection-style attacks when prompting for anything that handles user input; don't assume it's included by default just because the feature otherwise works.
Authentication and authorization
These are two different checks and both need to be explicit: authentication confirms who someone is, authorization confirms what they're allowed to do or see. A common, subtle bug is a route that correctly checks whether a user is logged in but never checks whether this specific user should be able to access this specific record — which lets one account read or edit another's data. This exact class of bug is worth testing directly if you're building anything with multiple user accounts, as covered in How to build a SaaS with AI.
Review discipline for agentic tools specifically
The more autonomous a tool is — running commands, installing packages, editing multiple files in one pass — the more a single approval covers a wider blast radius. Review diffs before merging, keep destructive or irreversible actions (deleting data, pushing to production, sending real emails) behind an explicit confirmation step, and use version control so any change is trivially reversible.
A pre-launch security checklist
- No API keys, secrets or credentials appear in client-side code or a public repository
- All user input is validated server-side, not just in the browser
- Every route or query that touches user data checks both authentication and authorization
- Dependencies have been reviewed, not just auto-installed and forgotten
- Error messages shown to users don't leak internal details (stack traces, database structure)
- You've tested what happens when a logged-in user tries to access another user's data directly by URL or ID