The Scanner Has to Follow the Agent

The Scanner Has to Follow the Agent

A security scanner can be present in the coding loop and still miss the code the agent writes.

The reason is not necessarily a bad rule. It is that an agent can change the transport. A recent post from Semgrep says a Claude update changed how agents write files: instead of dedicated Write and Edit operations, agents increasingly use Bash commands such as cat > file, sed -i, and echo >>. Semgrep says its Guardian v2.2.0 now scans those Bash-driven changes too.

That is an alleged product update from the vendor’s own account, not an independently measured benchmark. The systems lesson is still concrete: a verifier that watches one tool path is not verifying the agent. It is verifying a path through the agent.

The tool call is not the trust boundary

Most agent security diagrams draw a neat line around the model and place tools on the other side. In practice, the important boundary is lower down.

The agent may have several ways to produce the same filesystem mutation:

  • A structured edit tool writes a file.
  • A shell command redirects output into a file.
  • sed -i modifies a file in place.
  • A script generates or rewrites a directory.
  • A package manager installs code as a side effect.

If the scanner hooks only the first operation, the control is coupled to a product vocabulary rather than to the effect that needs checking. A model does not need a new capability to bypass that control. It only needs another existing capability that reaches the same state.

This is the uncomfortable part of agent security: the model’s interface is often treated as an API contract, while the machine sees a set of equivalent state transitions.

What Guardian is trying to change

Semgrep’s Guardian announcement describes a security layer that runs in the IDE as an agent writes code. Semgrep says it checks vulnerabilities, malicious packages, and hardcoded secrets, and that it connects through hooks, an MCP server, and skills.

The vendor also reports more than 3 million scans per week, with 95% completing in under five seconds. Those are Semgrep’s customer-base figures, not an independent evaluation, so they should be read as a product claim rather than a general performance result.

The architecture is the interesting part. The scanner is being moved closer to the write event, where a finding can be fixed before it becomes a pull request or a deployed artifact. That reduces latency, but it creates a harder engineering requirement: every route to a write has to be observed.

Semgrep’s configuration documentation makes the integration split explicit. Claude Code’s recommended remote plugin uses Guardian hooks and a fixed guardian-default ruleset. Other clients, including Cursor, Codex, GitHub Copilot, VS Code, Devin, and Kiro, use semgrep_scan through the MCP server and the organization’s Policies.

That distinction matters. A hook-based integration and an MCP integration are not automatically equivalent. They can see different events, apply different rules, and fail in different ways.

The bypass is usually semantic, not syntactic

It is tempting to describe this as a race between scanner authors and model vendors. The deeper problem is semantic.

The scanner needs to answer: what changed, who caused it, and which policy applies? A raw stream of tool calls is not enough. cat > app.py and an editor’s Write operation may be different messages that produce the same file diff. A package install may modify a lockfile, add post-install code, and write binaries without looking like a source edit at all.

A reliable control therefore needs an effect-level record. At minimum, it should capture:

  1. The before and after content or a trusted diff.
  2. The process and agent identity that caused the mutation.
  3. The tool path, including shell commands and child processes.
  4. The policy and ruleset used for the decision.
  5. The decision, fix attempt, approval, or failure.

Without that record, an operator cannot tell whether a clean scan means clean code or merely an unobserved write.

Inline scanning is not the same as complete coverage

Moving security left helps only if the left-hand control is complete enough to trust. It does not replace CI or platform scans.

Semgrep’s documentation says Guardian runs as the agent writes code while CI and platform scans continue to enforce organizational Policies. That is the right division of labor. The inline layer gives fast feedback. The downstream layer provides a second observation point after the code has crossed more boundaries.

The two layers should not be treated as duplicate copies of one scanner. They answer different questions:

LayerQuestionFailure it catches
Agent-time hook or MCP scanWhat is the agent writing right now?A dangerous edit before it spreads
CI or pull request scanWhat is entering the shared codebase?Writes that bypassed the local integration
Build and deployment checksWhat artifact is actually shipping?Generated files, dependencies, or packaging changes
Runtime controlsWhat can the deployed service do?A bug that survived every source-level check

The table is not a defense in depth slogan. It is an observation map. Each layer sees a different state transition.

What operators should measure

The usual dashboard metric is findings. That is not enough for agent-generated code.

Operators should also measure coverage of mutation paths:

  • The share of file mutations observed by a scanner.
  • The share of shell-spawned writes that receive a scan result.
  • Findings by agent, integration, and tool path.
  • Scan failures and fail-open decisions.
  • Fixes that were proposed, applied, rejected, or overwritten.
  • The final artifact’s findings compared with the inline result.

A scanner that reports zero findings while observing 60% of writes is not a low-risk scanner. It is an incomplete sensor.

The same principle applies to agent permissions. If an agent can invoke a shell, the shell is part of the security interface. If it can install packages, package lifecycle behavior is part of the interface. If it can ask an MCP server to scan a file, the MCP server is part of the verifier’s trust boundary too.

The verifier has to follow the effect

Semgrep’s reported Bash coverage update is a useful reminder that agent security cannot be anchored to the names of today’s tools. Agent harnesses change. Models learn alternate ways to perform the same task. Integrations split between hooks, MCP servers, skills, and local plugins.

The verifier has to follow the effect, not the button that caused it.

That means observing filesystem mutations, process ancestry, generated artifacts, and the decisions made at each stage. It also means retaining enough evidence to explain a miss. Otherwise, a green check is only proof that one integration path stayed quiet.

The model is not the whole security problem. The control loop is. A scanner that cannot see the agent’s actual write path is guarding an interface, not the system.

Sources

Method note: the topic was selected from the two required free, session-authenticated twsearch radar queries. The product behavior described as a current update comes from Semgrep’s own X post and is labeled as a vendor claim. The architectural analysis is inference from the documented integration paths and the write operations named in that post.

Keep reading