Threat assessment for coding agents, run as the final step of implementation planning.
A Claude Code / Codex plugin. Once your implementation plan is comprehensive and detailed — but before any code is written or the plan is presented — Ingrain Security threat-models the plan and folds the results back into it. It is read-only on your codebase: it never edits code.
- Repository: https://github.com/ingrainlabs/ingrain-security
- License: MIT
Security analysis is treated as the last step of planning, not a separate pass afterward. When a plan is ready, the plugin triages the change, and for security-relevant ("major") changes runs a full review: it enumerates threats, scores their risk, lets you choose which threats to address, proposes mitigations for the ones you picked, and lets you choose which mitigations to adopt. The selected threats and adopted mitigations become part of the plan the coding agent then implements.
The full spec lives in skills/ingrain-security/SKILL.md;
the short version:
- Triage first. Only "major" (security-relevant) changes get the full review; "minor" changes stop immediately with nothing to fold in.
- The review loop: threats → 0–100 risk score → Gate 1 (you pick which threats to address, 0–N) → org rules → mitigations → rule expansion → Gate 2 (you pick which mitigations to adopt, 0–N). Threat and mitigation drafts each pass through a critic with up to 3 revision rounds.
- Org rules in two passes. Your org's security rules are retrieved twice: once
from the selected threats, before any mitigation exists, and once more by
ingrain-rule-expanderafterwards — keyed on the mitigations actually proposed, so the search can ask what those concrete mechanisms imply. Both passes land in a rules sidecar next to the assessment. - Read-only workers. The orchestrator dispatches seven worker roles as fresh
subagents —
ingrain-relevance-triage,ingrain-threat-generator,ingrain-threat-critic,ingrain-risk-scorer,ingrain-mitigation-generator,ingrain-rule-expander,ingrain-mitigation-critic(defined underskills/ingrain-security/references/development/). Each uses only Read/Grep/Glob on your codebase; its sole write is its own section of the assessment file. - Two selection gates are yours. At Gate 1 and Gate 2 you decide, per finding, what gets addressed. Selecting none is always allowed.
- Then the code gets tested against the threats. Once the plan is implemented, the Testing phase grades how robust the applied mitigations turned out to be — see Verifying the implementation below.
The whole lifecycle, both phases end to end — Development before code, Testing after:
flowchart TD
subgraph DEV["Development — plan review, before code"]
planning([Plan is comprehensive & detailed]) --> triage[relevance triage]
triage --> majorQ{major?}
majorQ -->|minor| stop([Stop — keep planning])
majorQ -->|major| threats[generate threats → critic]
threats --> score[risk score 0–100]
score --> gate1{Gate 1: select threats 0–N}
gate1 -->|none| folded([Fold results into the plan])
gate1 -->|1+| rules[retrieve org rules]
rules --> mits[generate mitigations]
mits --> expand[expand rules — once]
expand --> critic[mitigation critic]
critic -->|needs-revision| mits
critic -->|approved| gate2{Gate 2: select mitigations 0–N}
gate2 --> folded
end
folded --> impl[coding agent implements the plan]
impl --> phase{assessment + adopted mitigations + branch delta?}
phase -->|no| nothing([Nothing to verify])
phase -->|yes| diff
subgraph TEST["Testing — negative testing, after code"]
diff["branch diff since the fork point<br/>committed + uncommitted"] --> scope[scope: selected threats + their adopted mitigations]
scope --> sidecar[read org rules from the sidecar]
sidecar --> verify["one threat-verifier per selected threat<br/>+ general-instruction pass"]
verify --> conclude[conclude robustness: weak / adequate / strong]
conclude --> record["record Robustness on threats + mitigations<br/>Latest stage: testing"]
record --> weakQ{any threat weak?}
weakQ -->|no| pass([All selected threats closed])
weakQ -->|yes| revisit([Report residual paths])
end
revisit -.->|revisit & re-verify| impl
Planning adopts mitigations; the Testing phase of the same skill checks they were built. ingrain-security
has two phases and picks between them from repo state: Development is the plan review above,
run before code; Testing (spec:
skills/ingrain-security/references/testing/verification-pass.md)
runs after you implement a task whose plan went through that review. It measures how robust
the applied mitigations are — by negative testing: whether the threats the plan selected
can still be realized against the code as built. The threats define the scope. It locates the
task's assessment file, reviews the branch diff since this branch diverged from its parent
(committed and uncommitted alike), and dispatches one read-only ingrain-threat-verifier per
selected threat — each holding that threat, the adopted mitigations meant to close it, and the
org rules behind them from the rules-<…>.md sidecar. A threat the plan selected but adopted
nothing for is tested too.
Each verifier justifies before it concludes, and the skill weighs that justification on its
evidence rather than taking the level word at face value: a level the cited file:line does
not carry does not stand, and the level recorded is the orchestrator's own conclusion.
It reports each threat's robustness — weak (the threat can still be realized), adequate
(its realization routes are closed), or strong (closed broadly and backed by artefacts such
as adversarial tests) — with evidence and, for weak, the concrete residual path by which the
attack still gets through. Whether a mitigation matches the wording of its Description is not
the bar; a control built to spec that still leaves its threat reachable is weak coverage.
Judging robustness is left to the analyzing agent — the levels define what was tested, not a
rubric to execute. It marks the assessment checked by recording each threat's Robustness
and, on each covering mitigation, its Justification + the Robustness it inherits, and
advancing the file's
stage to testing. It writes no code, runs no user gates, and makes no ingrain CLI call:
each verifier reads the org rules back from the rules-<…>.md sidecar Development persisted.
- On the skill's own trigger. The skill description tells the agent to run Testing after it implements code for a reviewed plan, before presenting or committing it. Nothing enforces this at the turn boundary — it is the agent acting on the description, so treat it as a strong default rather than a guarantee.
- Manual. Invoke the skill after implementing — e.g. "Use ingrain-security to verify the mitigations I just implemented." Naming the phase is enough to select it; otherwise the skill routes on state (an assessment for this task, carrying adopted mitigations, plus a non-empty branch delta — committed or uncommitted → Testing). This is the reliable way to run it.
If a task has no assessment (or no adopted mitigations), there is nothing to verify.
- A single assessment file written into the
.ingrain-security/folder at your project root —.ingrain-security/assessment-<branch>-<task>.md(branch- and task-keyed, minted by thescripts/assessment-pathscript). It is the workers' shared hand-off medium and its own persisted record — written in place, no temp copy — and is git-ignored by default (share one withgit add -f <file>). - The selected findings, folded into your plan.
Writes to that one file are approved automatically — by a PreToolUse hook on Claude
Code and a PermissionRequest hook on Codex — so a review does not interrupt you with a
permission prompt on every edit. The grant is deliberately narrow: only assessment*.md
files sitting directly in the project's .ingrain-security/ folder, and never through a
symlink. On Codex, where an edit is an apply_patch, the patch must touch nothing but
those files and may only add or update them. Everything else — including the folder's own
README.md — still goes through your normal permission prompt, and the hook can only
skip a prompt, never block an edit you asked for. Codex asks you to review and trust the
hook once, via /hooks.
Add the marketplace to your host, then install the ingrain-security plugin:
# Claude Code
/plugin marketplace add ingrainlabs/ingrain-security
# Codex
codex plugin marketplace add ingrainlabs/ingrain-security
Installs are pinned to the v<version> git tag, not the default branch — you
only ever receive tagged releases.
Full setup — including the ingrain CLI binary, API token, and configuration — is
documented at Getting started.
- Automatic. A SessionStart hook injects the skill into every session, so the
agent runs the review at the end of planning. On Claude Code, a
PostToolUse:ExitPlanModehook also nudges it to run before code is written. - Manual. Invoke it via the Skill tool, or just ask — e.g. "Use Ingrain Security to threat-model this implementation plan before I write code."
- At Gate 1 (threats) and Gate 2 (mitigations), you choose what gets addressed — each finding is an individual include/exclude decision, and excluding everything is a valid outcome (recorded as accepted risk).
| Platform | Requirement |
|---|---|
| macOS / Linux | System bash + coreutils — nothing extra to install. |
| Windows | Git for Windows is required. |
Why Git for Windows. The plugin's hooks are bash scripts run through
hooks/run-hook.cmd, a cmd/bash polyglot wrapper. On Windows
it invokes them with the bash it finds at C:\Program Files\Git\bin\bash.exe or any
bash on PATH (Git Bash / MSYS2 / Cygwin). Installing Git for Windows — whose
bundled Git Bash satisfies this — is the simplest way to meet the requirement.
Graceful degradation. If no bash is found on Windows, the wrapper exits silently: the plugin still installs, but loses the SessionStart context injection and the assessment-folder seeding, so the automatic review won't fire. You can still invoke the skill manually.
Read-only guarantee. The workers never edit code. The only writes the review makes are the assessment file and the findings folded into your plan.
Sandboxing & network access. The review's only outbound network calls are the
read-only ingrain context security_rules lookups of its two rule-retrieval passes —
one per distinct question it needs org guidance on — which fetch your org's security rules
(via INGRAIN_SYNC_URL + API token). If you run your coding agent under a sandbox
that restricts network or command execution, allow those ingrain context CLI
runs so org-rule retrieval works. Without it the review still
completes — it just degrades gracefully and proposes mitigations without your org's rules.
The assessment folder is git-ignored. .ingrain-security/ is ignored
by default. To share a snapshot, force-add it: git add -f <file>.
- Release process and versioning:
.github/README.md - Test suite (Deno-based):
tests/README.md
MIT — see LICENSE.