See how Temporal built hands-off onboarding in 48 hoursSkip to main content

Agentic Threat Modeling: Shipping secure code at machine speed

Written bySam Stewart

Published

An agent sends a pull request, changing a feature that involves sensitive credentials. The tests pass. The feature works. But the security assumptions may have changed.

  • Who should access those credentials?
  • Who actually can access those credentials?
  • What are the risks this change is introducing?

Those questions have to be answered as fast as the code ships.

Serval builds AI agents that take action inside other companies' IT systems. Our automations reset passwords in Google Workspace, grant access in Okta, provision licenses, and handle the credentials that hold all of it together. Customers give us that access because the alternative is repetitive, tedious, manual work. They keep giving it to us because every automation we ship is deterministic, scoped, and auditable.

That standard has to apply to how we build, not only to what we ship. Coding agents now write a meaningful share of the code behind those automations, and they work faster than any review process designed for people typing.

At Serval, we’ve deployed the open source tool threatcl to bring threat modeling into our engineering workflow. Our threat models live alongside the code, change through pull requests, and are checked in CI against shared security requirements. We also contributed the Invariants feature that shipped in Threatcl 0.6.0, which makes those guardrails deterministic and understood by agentic harnesses.

The goal is to give engineers and coding agents the fastest possible security feedback loop they can use while building.

Threat Modeling: a shared understanding of risk

Threat modeling starts with understanding what you’re protecting, what could go wrong, and which controls address those threats. That understanding becomes harder to maintain when it lives in a document outside the development workflow. A new integration ships. An authentication flow changes. The implementation moves forward, while the document still describes an earlier system.

Done well, threat modeling is one of the most powerful ways to build secure software. But that work takes time and expertise, and stretched teams often struggle to give it the attention it deserves. Agents change that equation. They can examine the code, map trust boundaries, and draft model updates as the implementation changes, giving engineers a concrete starting point to challenge and refine.

Threatcl lets us express that understanding as code by using HCL, the configuration language familiar to anyone who has worked with Terraform, to describe assets, threats, controls, and data flows.

At Serval, material changes to trust boundaries require a corresponding threat model review in the same pull request. That includes introducing an external dependency, creating a new path for credentials, or changing invariants such as “no endpoints should exist without authentication.”

The reviewer can see the implementation and its security reasoning together. The model records which controls are implemented and which remain gaps. Its scope is explicit.

For a coding agent, that creates useful context. The agent can read the existing model, examine the implementation, and propose updates as part of the work. Security requirements become something it can act on before handing the change to a reviewer.

But putting a threat model in version control only solves part of the problem.

Introducing: threatcl invariants

We found that a model could be syntactically valid while missing things our security standards required. Threatcl could parse the file successfully, yet the model might leave an asset unclassified or omit a key security control.

We raised that gap with the threatcl maintainers and contributed Invariants upstream, free and open source for all.

Invariants let an organization define rules that run against all parsed threat models. The rules live in a separate HCL file and apply consistently across all models.

For example, at Serval we require all internet facing endpoints to also have a corresponding audit log event, and this maps to a static analysis linter which runs deterministic rules to enforce this, in code.

An example of the recently released threatcl Invariant

When an applicable model fails that rule, validation fails. The output identifies the violation so the author can address it.

We also use invariants to check that threats reference declared assets, sensitive assets have threat coverage, and unimplemented controls explain the remaining gap. These are recurring review requirements that can be checked consistently by a machine.

That consistency is critical when agents participate in development. An agent can propose a model update, run validation, inspect the failures, and revise its work. Engineers reviewing the change can then focus on the questions that require higher-level judgment: whether the model reflects the implementation, whether a threat has been missed, and whether a mitigation is sufficient.

Tying it all together, at speed

A passing threat model check has a precise meaning. We pair model validation with code-level tests and static analysis for that reason. The model describes the security assumptions and controls - the why behind a change. SAST and test cases check the properties they can enforce. Threatcl connects the two.

Changes that don’t make a material difference to threat boundaries can move quickly, provided CI and existing checks remain green. Potentially interesting changes are flagged for further security review and discussion.

Exceptions also need the same visibility. Invariants support exemptions with required justifications, also committed as code. That lets us record an exception without weakening the rule for every other model, giving a fine-grained level of control that AGENTS.md and general context engineering can’t. We can further reduce friction by using the “warning severity”, allowing for new security boundaries to be introduced in soft-fail mode, to nudge engineers and agents to address existing violations, before dropping the hammer on enforcement.

We’ve previously written about the importance of boundaries when deploying AI. The same principle informs how we build with it: agents need explicit requirements and useful feedback throughout the SDLC.

Threatcl gives us a shared, reviewable description of security expectations. Invariants make more of those expectations checkable during development. Contributing the feature upstream makes that approach available to other teams facing the same problem.

As coding agents take on more engineering work, we want security reasoning to travel with every meaningful change: it’s the only way we can accelerate security to machine speed.

You may also be interested in