Five Ways to Keep Your AI Agent From Shipping Insecure Code
Part 3 · Beyond the Prompt series
AI agents write code fast, and they write insecure code with exactly the same confidence as secure code. Five practices worth building into your workflow.
An agent can easily output a SQL query wired up from string concatenation, an endpoint with no auth check, or an API key pasted into a config file, and it will mark every one of them as done in its task list. Correct, test-passing code is not the same as secure code.
Security is a specialized field and this short article is no substitute for threat modeling or for people who do this for a living. That being said, these 5 practices have really helped build out my spec-driven workflow and meaningfully raise the security floor for anything I build with an agent.
1. Put security requirements as acceptance criteria in the spec. Most insecure code comes from security being assumed that it wastaken care of by default. Write it down where it cannot be missed: reject unauthenticated requests, uses parameterized queries for every database call, etc. When acceptance criteria become tests, those expectations get checked on every run instead of being implied.
2. Encode the non-negotiables in your constitution. Your always-loaded project rules (like a CLAUDE.md file) are the home for the things that must never be violated. Things like: pull secrets from the environment and never from source, perform an explicit authorization check on every endpoint, pin your dependencies. An agent given those rules carries them into every feature without being reminded.
3. Keep secrets out of the context window, the repository, and the model's
output. This risk is specific to AI-assisted development and people miss it all the time.
Agents read and write files, and you paste context into prompts, so a key dropped into a prompt,
a committed .env, or a secret echoed into a log is a direct exposure. Keep
credentials in environment variables or a secret manager, never hard-code them, never paste them
into a session, and run a secret scanner over your commits so a slip is caught before it
ships.
4. Validate and authorize at every trust boundary, and verify the agent actually did. The common vulnerability classes, injection, broken access control, server-side request forgery, unsafe deserialization, all live where untrusted input crosses into a trusted operation.
5. Treat every new dependency as a potential security risk. Agents add packages freely, and the supply chain has been a real attack surface more than usual. Require a justification for any new dependency, pin versions, run dependency and static-analysis scanning in your pipeline, and keep what you depend on patched. A dependency you did not choose intentionally is one you cannot vouch for.
None of this makes an application secure on its own, it just cuts down the obvious failures. It puts security inside the method you are already using instead of leaving it until the end. Real security work, threat models, reviews by specialists, and defenses matched to your specific risks, goes well beyond any list and deserves that dedicated attention.