Apps built with a coding agent go unscanned for a structural reason: every pipeline gate assumes someone onboarded the app first, and the person who built it never learned what DAST is. The fix is to put the runtime scan inside the agent's definition of done, with one record left in the repository as proof.
Key takeaways
- Coverage does not fail on the apps you onboarded; it fails on the ones nobody did.
- The fix is a completion contract: the agent's definition of done includes a runtime scan that leaves a record in the repo.
- NightVision ships it as an org-level agent-instructions block, an
/app-security-scanskill, and a one-call MCP harness that runs source intelligence over the repo and starts the DAST scan. Once the scan finishes, the SARIF export links request-level findings (injection, XSS, and similar) to the endpoint, the proof-of-concept payload, and the source file:line, where discovery produced a spec. - The rule is probabilistic per turn. Pair it with a harness-level gate on the scan record.
Coverage decays one app at a time
Coverage has a denominator problem: onboarded apps get scanned and the dashboard stays green, but the inventory only knows about apps someone registered.
Coding agents broke the denominator. Gartner projected in 2021 that 70% of new enterprise applications would use low-code or no-code technology by 2025, up from less than 25% in 2020, and separately predicted that active citizen developers at large enterprises would outnumber professional developers at least four to one by 2023. An analyst in finance describes a reporting dashboard and has a running app with real endpoints by lunch, and it never entered the pipeline security was designed to watch. It is the builder who cannot see the vulnerability from Vibe Coding Security: Your New Attack Surface, multiplied across every team.
The failure is quiet by construction. Nothing turns red when an app is never onboarded. Coverage does not drop. It stops meaning anything.
Why the gate never fires
This is not a discipline problem, fixable with a policy and an email. The gap is structural, in two halves.
The first half is the builder. Someone who builds through an agent has usually never heard the term DAST and does not know their app exposes an API.
The second half is the gate. Every control a mature program owns assumes a prior human act: someone onboarded the app. That act is exactly what the builder does not know to perform. MCP Solves Half of Your AI Security Problem argued that a developer-workflow protocol closes the loop for engineers who already drive an agent and reaches nobody else. This post answers the other half with one observation: every one of these builds has a participant who can be taught to run a scan. The agent.
The definition of done is the only place the control can live
There is exactly one moment in an agent-built app's life where a control can attach without asking the builder to do anything.
Not the pipeline: the app may never enter one. Not a source-only review: reading code alone cannot say whether a flaw is reachable at runtime. Not an inventory sweep: it finds the app weeks later. The moment is the agent's own completion step. An agent already has a definition of done (tests pass, lint is clean, the branch builds). That is the lever.
Put the runtime scan inside the definition of done and the onboarding problem inverts. The app no longer has to be registered before it can be tested, because building it is registering it. AppSec sets that standard once, at the org level, for every repo the org's agents work in.
Four ways to get an app scanned
| Developer remembers to scan | Pipeline gate on onboarded apps | Agent completion contract | Contract plus harness gate | |
|---|---|---|---|---|
| What triggers the scan | A person decides to | A CI job on a registered app | The agent's definition of done | The contract, checked by a hook or CI on the scan record |
| Covers apps nobody onboarded | No | No | Yes, when the rule fires | Yes, and a missed turn is caught |
| Record left behind | Whatever the person saved | Pipeline logs | A manifest with a scan ID in the repo | The same manifest, now enforced |
| Failure mode | Silent | Silent for unregistered apps | Probabilistic per turn | Loud: the turn or build fails |
The pipeline column is not the loser: for a service engineering owns, a CI gate is stronger enforcement than any agent rule. Layers, not rivals.
How it works
NightVision ships the completion contract as three pieces. The MCP mechanics are in DAST MCP Server: Runtime Evidence for AI Coding Agents; this covers what sits on top.
The org-level agent-instructions block. It goes in the file the agent reads: CLAUDE.md for Claude Code, AGENTS.md for Codex and Cursor. Whenever the agent creates or materially changes a web app, API, or backend service, it is instructed to run a scan as part of finishing, without the developer asking. The operative sentence:
Work on a new or materially changed app is not complete until either .nightvision/manifest.json exists with a NightVision DAST scan ID, or you have stated the exact blocker that prevented DAST (app would not start, no project, not authenticated, target unreachable).
The block carries no credentials: every action runs under the developer's own NightVision account, configured in the managed MCP server, so no shared token goes into the repo.
The /app-security-scan skill. The block says when; the skill says how: pass the app's source directory and URL, make one harness call, report what discovery produced, poll to a terminal status, and export SARIF from the same source path so findings stay source-linked. It installs into Claude Code, Codex, or Cursor.
The run-app-security-scan harness. One MCP call that runs, in order: preflight (auth, project, reachability, with a structured blocker if any is missing); source intelligence over the repo, which reads the code and generates an OpenAPI spec of the routes it declares; target create or update with that fresh spec; and a DAST scan, authenticated with whatever app credential the agent passes (an existing auth profile or a Playwright login script), relayed through Smart Proxy automatically when the app is on localhost or a private network. Every run writes .nightvision/manifest.json into the repo with the scan ID, or a record of a run that did not reach DAST.
Two guardrails keep the contract honest. The export refuses to emit an empty SARIF for a scan that is still running, or for a failed scan that produced no findings. And a scan that succeeds with zero findings and no fresh spec from discovery is marked coverage_suspect, not clean.
On source-discovered API scans, request-level findings carry the endpoint, the proof-of-concept payload, and the handler's source file and line: the shape an agent can act on and a reviewer can check. The case for that linkage, and its limits, is in Source-Linked DAST.
What one run looks like
The run was against javaspringvulny, a deliberately vulnerable Spring test app with its source on the developer's machine, running in Docker on localhost:9000 and reached through the relay because localhost is not cloud-reachable.
The request was plain language: security-test the running app and say what is exploitable and where in the source. That loaded the skill; one run-app-security-scan call followed. Discovery read the source and produced a spec covering 36 endpoints; the target took the fresh spec, and the scan started through the relay.
At a terminal status the agent exported SARIF and summarized. 44 findings, 35 of them source-linked; the 9 that were not are configuration-level header and cookie issues with no fixable source line. Two were SQL injections:
/api/basic/items/search/, payload', declared atBasicAuthItemController.java:23/api/token/items/search/, payload', declared atTokenItemController.java:23
Each line is the endpoint handler the request came through, the entry point rather than the sink. When asked to fix the finding, the agent opens the handler, follows the named parameter into the service that consumes it, and reaches the sink at SearchService.java:33. The fix is a parameterized query, the verification is a rescan, and the pull request goes to a person.
An earlier run matters more. On an auth-limited run against the same test app, the scan returned only configuration-level results, the harness flagged the run coverage_suspect, and the agent diagnosed the coverage gap instead of reporting the app as clean. A scan that tested nothing and said "no issues" is worse than no scan.
The honest part: a rule is not a gate
An agent-instructions rule makes the agent do the right thing in the common case, not on every turn. On some fraction of turns, a long session or a compacted context, it will not fire, and you will not know which. Nobody should size a compliance claim on it.
So do not stop at the block. Pair it with a harness-level gate that does not depend on the model's judgment: a Stop or PreCompact hook in Claude Code, or a CI check in any pipeline, that fails the turn or the build when a new or changed app has no .nightvision/manifest.json carrying a scan ID. That hook is a recommendation for your own harness, not something NightVision ships.
None of this asks a builder in finance to learn what DAST is. It asks their agent to finish the job. AppSec sets the rule; the agent absorbs the onboarding work that was never going to get done by hand; a human approves what merges. Determinism on the finding, agents on the fix, humans on the merge. None of it shrinks the AppSec team. It is the only thing that scales one.
Frequently asked questions
Why do apps built with coding agents go unscanned?
Because the person who built it never learned what dynamic application security testing is, so they never ask for a scan, and every pipeline gate assumes someone onboarded the app first. The app is not skipped by the scanner; it never reaches one.
Can the scan reach an app running on localhost?
Yes. For a target on localhost or a private network, the harness routes the scan through the Smart Proxy relay automatically. Keep the MCP server running so the relay stays up.
What does the agent get back from the scan?
Runtime evidence. On source-discovered API scans, request-level findings such as SQL injection carry the endpoint, the vulnerable parameter, the proof-of-concept payload, and the source file and line of the handler that declared the route (the entry point, not always the sink). Configuration-level findings such as missing headers carry no fixable source line (either none at all, or a line pointing at whichever handler the response was observed through); the fix belongs in the app's security configuration.
Does the instructions block make the scan fire on every turn?
No. It is reliable in the common case but probabilistic per turn. For hard enforcement, pair it with a harness-level gate, such as a Stop or PreCompact hook or a CI check, that fails when a new or changed app has no manifest with a scan ID. That gate is yours to configure.
Does this reduce the need for an AppSec team?
No. It removes the onboarding step that was the throughput limit. Agents absorb the scan, the triage, and the draft fix, then rescan to verify it. The AppSec team keeps the work only it can do: set the standard in the org rule, review the fix, and approve the merge.
If your developers build with Claude Code, Codex, or Cursor, see the contract run against one of their apps. Schedule a demo to see a live run, or Start Free and add the block to a single repo. See also What You Should Know About Application Security Testing.
Put the scan where the apps are being built
If your developers build with Claude Code, Codex, or Cursor, see the contract run against one of their apps. Schedule a demo to see a live run, or Start Free and add the block to a single repo.
Related readingFor the broader map of testing methods and where a runtime scan sits among them, read What You Should Know About Application Security Testing. For the evidence an agent needs before it can draft a fix, Source-Linked DAST.