September 10, 2026
0 mins read Stopping new security issues in agent-generated code from being deployed is, architecturally, a solved problem. Prevention is the act of keeping a new vulnerability in code from reaching production at any point in the development and release process, including but not limited to preventing its introduction in a feature branch. There are distinct points in the agentic development lifecycle where security can be introduced, each suited to a different kind of control, and the mapping between them is well understood. Applying it inside an organization while the software development lifecycle is actively shifting makes that mapping difficult to apply.
You cannot prompt your way comprehensively #
The idealized version of security in agentic development is a single instruction: tell the agent to write secure code, put it in the system prompt or the harness configuration, and let it go to work.
Figure 1. The instruction that feels like a control.
Guidance in the context window does change what an agent produces, and the effect is real enough to build on, but an instruction is not a constraint. It shifts the probability of what gets written, but does not decide it. That holds for a one-line rule, and it holds for a carefully written skill. This is a property of how these models work (considering all inputs and making judgments about their relative priority), regardless of the quality of your prompt.
AI-generated code remains susceptible to the same classes of vulnerabilities that human-written code has always had. Instruction alone does not change that, and no amount of prompt craft will. So the useful question is where everything else goes.
“Shift in” is the new “shift left” #
Three costs rise as security moves outward, away from the moment the code is written.
Figure 2. All three rise together as security moves outward.
Tokens are the obvious one. A deterministic scan's cost is a rounding error next to a model call, and the gap widens every time you ask a model to reason across more of the codebase.
Human attention is the second. An issue caught while an agent is still working never becomes a ticket, never gets triaged, and never interrupts someone who is split across multiple tasks.
The third is getting the fix right. An agent working in the inner loops still holds the original prompt and spec, so when it corrects something, it can confirm that the result is both functionally intact and secure because it knows what the code was supposed to do. Push the same finding outward, and that context is gone. Correctness has to be re-established from outside, through unit tests, smoke tests, and integration tests running before and during CI.
An agent extending existing functionality also relies on the test suite in the inner loops, because it needs to know it hasn't broken something it hasn't seen. But it leans less, as it still holds the prompt and can reason about what the change was meant to do rather than inferring intent from whatever happens to pass. The further out a fix moves, the more of that burden shifts onto coverage alone.
That is the case for pushing security inward. The reason it does not happen on its own is that the pressure running the other way is stronger.
Security is friction #
None of this is new. Security costs time, and putting time into a developer's flow has always been the hard part of this job. It's why Snyk successfully pioneered shift left in DevSecOps starting ten years ago.
The agentic era magnifies it rather than changing it. Organizations are underwriting AI adoption against multiples on developer productivity. And when the expectation is a step change in throughput, anything that slows the loop is not a tradeoff conversation. It gets removed.
So the question is not whether to add security controls but instead where each one can sit without costing more than it saves.
The lifecycle is a stack of loops #
Laurie Voss's loop model is one of the cleanest descriptions of how software gets built now: a set of nested loops, each closing on its own signal.
- The execution loop completes an instruction and exits on feedback from the environment, whether that is a test result, an API response, or the contents of a file.
- The task loop completes a specification.
- The product loop ships.
- The system loop improves the whole thing over days and weeks.
- The oversight loop is where a human sets goals, allocates a budget, and decides what matters.
Figure 3. The loop stack, after Laurie Voss's What the hell is a loop, anyway?
Inside the execution and task loops, the work is still open, and a finding can still be fixed before the loop completes without human intervention. From the product loop outward, there must be significant trust in test coverage, otherwise human review is necessary.
Two caveats before we build on this. First, adoption is uneven: there is a spectrum of adoption of agent development, even within companies. Plenty of teams are not running agents in every one of these loops, and many still have people working well inside the inner ones rather than only at oversight. The loops hold either way, because they describe when a piece of work closes, not who closed it.
And second, if you take the agentic vocabulary out, most of this is how software has been built for a long time: you iterate on a change, you finish a unit of work, you ship, you improve the system, and someone decides what is worth doing next. What has changed is the speed, and who (or what) is at the keyboard.
The risks you can name in advance #
Some risks are entirely predictable: SQL injection, cross-site scripting, hardcoded secrets, weak crypto defaults, and the most common infrastructure-as-code misconfigurations. We know exactly what we are looking for, and an agent can be told how to avoid it before it writes a line.
The control is guidance in the agent's context: system prompts, harness configuration, and skills covering the risks a team most wants to stop producing. It is the cheapest control available, because the cost is paid once in the context window space rather than per issue checked. Nothing runs, and nothing is evaluated; the guidance is simply there.
Some of it is already in place without anyone deploying anything. Harnesses include system prompts that carry some of these directives by default. As an example, Anthropic documents each of its models' system prompts. On top of that, many organizations are building shared skill registries, sometimes with application-specific skills describing how their own teams build, which means a security skill is not a new kind of artifact to distribute. It is another entry in something that already exists.
The limit here is context. Every instruction competes with the ones already in the window, and the full range of vulnerability classes into an agent's context dilutes the guidance that matters most for the sake of risks that rarely surface. You have to ration, which means something else has to catch what you leave out. And context is only half the constraint. Even with unlimited room, some risks cannot be written into an instruction at all, because when the instruction was written, nobody knew they existed.
The issues nobody could have told the agent about #
When developers or agents select a package, they often pick the latest version because it's current and does what they need it to do. If a vulnerability in that version was disclosed the same week, neither of them would know. The model was not trained on it. No skill could have covered it, because the disclosure did not exist when the skill was written. Expecting prevention-by-instruction to handle that is not a reasonable ask of anyone.
Then there is everything you rationed out of the previous stage. The long tail of risk that cannot go into a system prompt or a skill without polluting the context, but which is perfectly real and perfectly detectable. From the agent's position, these two categories of risk are the same problem: it was never told to look out for them.
Both need a test that runs exhaustively rather than selectively, fires while the work is still open, and returns fast enough that the agent is still there to act on it. And it should not stop at finding. If the agent can fix what the test surfaces and then re-run it, the loop closes without a human being pulled in at all, which is the only version of this that survives contact with a team measuring throughput.
Trusted Output Assurance (part of Evo Agentic Development Security) does this through hooks and the CLI. A scan fires as files are written, and again when the agent finishes its planned work, so newly introduced issues surface and get fixed before the spec closes – all within the inner loops. Package health checks, secrets scanning, and malicious code defense run on the same path.
An agent that fixes everything handed to it will sometimes rewrite working code to satisfy a finding that was never real. That is part of why this stage belongs to deterministic engines rather than probabilistic ones, and it makes the false positive rate something to test when you are choosing what runs. You should also understand what happens when the engine and the agent disagree about a detected finding. Snyk optimizes for both. A control only earns a place in the inner loops if it is right often enough to act unsupervised. Where confidence is lower, the finding belongs further out.
A control like this is worth exactly what its adoption is, and adoption is where inner-loop security has always struggled, because it depended on each developer setting it up. That part is straightforward now. Organizations push Trusted Output Assurance out via MDM to developer machines and bake it into sandbox templates, so it is already there wherever code is being generated, and what is running on which machine shows up centrally rather than having to be taken on trust.
What fast, deterministic engines struggle with #
Authorization and business logic flaws are a different problem. Broken object-level authorization, IDOR, tenant isolation failures, and multi-step abuse. These are well understood as classes, and rules-based engines are genuinely bad at finding them, because the flaw is semantic rather than syntactic. Nothing in the code looks wrong. What is wrong is the relationship between things.
LLM-based scanning of the assembled codebase is what works here. In practice today, that means an organization prompting a model to go looking, either by hand or as a triggered agent invocation in a pipeline, sometimes through a vendor and sometimes by pointing a frontier model at the repository directly.
Run the same security review five times over the same code, and nearly half of what the model finds on its own turns up in only one of the five runs. That is Snyk VulnBench JS 1.0, measured across 300 runs of the same review.
Those one-off reports are not wrong, and VulnBench documents plenty of them that look like genuine gaps in coverage rather than noise. But a single run is not a decision. Confidence has to be bought with repetition, which is why this is the first point where cost per finding becomes a real line item rather than a rounding error.
What changes at this stage is not how long a scan takes but what it has to look at. Every control before it is incremental. A skill fires as the agent reaches for a pattern. A scan covers the one file just written rather than the dozens touched across a session. Each of them is absorbed into work that was already happening. Semantic analysis of the assembled codebase cannot be, because there is nothing to reason about until the pieces are together, so it runs as a step of its own, and its cost is added to the loop rather than absorbed inside it. The time that loop already took was the agent working, not slack to wait in, and a full pass can easily double its length. That assumes a clean result: anything it finds has to be fixed, and the analysis run again, so the cost compounds rather than adds. All of which is why this lands after the agent has moved on.
Each of those cycles also leans harder on the test suite. The prompt is gone by then, so coverage is the only thing standing between a security fix and a broken feature, and every rerun asks it to hold again. At most organizations, coverage is not close to the level where a fix can land unattended, so a person ends up reviewing it.
This is exactly where Snyk is heading with the future of agentic AppSec. Expect more on this in the near future.
What only shows up under (pre-prod) attack #
The last category only appears when something is running. Multi-step exploit chains, workflow abuse, prompt injection against a deployed agent, data exfiltration paths that exist only because of how three components happen to interact in your environment.
The control is adversarial testing: pentesting and AI red teaming against a real application. The kinds of weakness being probed are known, but the work is exploratory. The application is the starting point, and the bounds are not fixed in advance, so what surfaces is whatever the system turns out to permit.
This is where Evo Continuous Offensive Security sits, and it is worth being specific about what is doing the work, because it is not a scanner with a model bolted onto it. An orchestrating pentest agent runs specialized sub-agents against a live target. A separate validator agent pushes back on what the others report and builds a working exploit to prove it. That last part matters because exploratory model-driven testing produces plausible-sounding findings unless something forces them to hold up, which is why every finding ships as a runnable proof-of-concept rather than a hypothesis.
Three of those sub-agents (business logic, access control and authorization, and exploit chaining) are working on the same semantic categories that the previous stage needs. Productizing these and similar engines into the workflows of the prior stage, as those workflows settle, is work already underway.
It can run against pre-production as a release gate or immediately after a release to inform what to work on next. Historically, this was an annual or twice-yearly compliance exercise. Organizations are running it far more often now, which is the right instinct, because adversaries are not on an audit schedule.
There is nothing to attack until something is running, which is the whole reason this cannot happen any earlier.
What the agent knew, and when it could act #
Every control above turns on the same two things: whether the agent could have been told before it wrote the code, and whether the answer arrives while it still holds the prompt. Those two questions place all four controls, and they explain why the sequence is not a matter of preference. Each control describes lands in one of the four boxes below.
Figure 4. The four controls, in the order the two answers put them.
Why this is harder in practice #
The blueprint is straightforward. Operating it inside a real organization is not, and the reasons have very little to do with security.
Most organizations do not have a settled agentic development lifecycle yet. The tools, the harnesses, and the architecture they are standardizing on are still changing, sometimes quarter over quarter. The vendor landscape is moving just as fast, so even where a choice has been made, there is real hesitancy to commit to anything resembling a one-way door. All of that surfaces as unclear ownership, because when the shape of the lifecycle is still in flux, so is the question of who is responsible for which part of it. Authorization and logic flaws tend to belong to nobody in particular right up until an incident assigns them to someone.
None of this requires a clean slate, which is the part worth holding onto. Almost every organization already has a pre-deployment security gate, and that gate is doing real work. It is not the thing to rip out while you figure out the rest. These injection points layer on top of what is already there, and they can be adopted one at a time, in whatever order matches where your lifecycle has actually settled. Putting deterministic scanning inside the loop does not require you to have resolved who owns adversarial testing.
That also tells you what to look for when you are choosing tools for any of these stages. Favor controls that are:
- Quick to stand up
- Minimally disruptive to how developers already work
- Easy to adjust or remove
The second is often underweighted. In the inner loops, a control that hands work back to a human has already lost, and so has one that produces a queue of AI-authored pull requests for somebody to review. Both take a security check and turn it into someone else's backlog, which is where controls go to be quietly switched off.
Further out, a human is harder to avoid. Test coverage at most organizations is nowhere near the level where an autonomous fix can be trusted to land, so somebody reviews it, and that is the honest state of things today, rather than a tooling failure. Harnesses are getting better at running the suite unprompted, and coverage climbs where agents write the tests, too, but nobody should plan around either having already arrived. Which is one more reason to catch what you can while the agent still holds the prompt, because that is the one place a human does not have to be.
The first and third are what make any of this safe to start while the ground is still moving. A control you can stand up in an afternoon, reconfigure centrally, or remove entirely, is one you can adopt before you have settled what your lifecycle looks like. Right now, that property is worth more than any individual capability.
Trusted Output Assurance itself distributes through MDM and holds its configuration centrally, so changing what runs does not mean editing Jamf or Intune policies or rewriting deployment scripts. Continuous Offensive Security needs your application URLs and a set of credentials, so there is no build-out to justify before it returns anything. Neither commits you to an architecture you have not settled on yet.
Prevention now, remediation next #
Prevention is solved in the sense that matters. The points exist, the controls exist, and which control belongs where is known. But doing it is work, and the (AI)SDLC is still evolving under us.
Remediation is a different story. Deterministic scanning inside the loop stops you from adopting a package with a known-bad version at the moment you adopt it. It does nothing about the package you adopted eight months (or even eight years) ago that got a CVE last week. That backlog grows from two directions at once: years of accumulated findings that were never fixed, and a continuous stream of new disclosures landing against code already in production. Good prevention does not shrink it, but it stops making it worse.
This problem deserves its own conversation. In the meantime, the prevention side is available now, and the first move is smaller than it looks: pick the point in your lifecycle that is most stable and add the right control.
Where Snyk fits, with the two controls named above:
Trusted Output Assurance brings security into the agent's loop, scanning and fixing as code is written.
Continuous Offensive Security tests the running application and returns findings with a working proof-of-concept.
Both are available today, and everything you need to evaluate them yourself is in the documentation.
Or hand it to your agent:
Read https://docs.snyk.io/agent-security/evo-by-snyk/agentic-development-security-ads https://docs.snyk.io/agent-security/evo-by-snyk/agentic-development-security-ads/activation-and-deployment and https://snyk.io/evo/continuous-offensive-security/. Tell me how Trusted Output Assurance and Continuous Offensive Security would fit the way this repository is built, tested, and deployed. If Trusted Output Assurance is a fit, tell me what's involved in setting it up and guide me through its configuration. Do not print the values of any keys, tokens, or credentials you find.