type: concept title: "Agent-safety threat model" description: "The threats the agent-safety and agent-tools surfaces are designed to stop, and the mechanism that stops each one: envelope forgery, replay, budget bypass, receipt tampering and plan-fingerprint mismatch."
Agent-safety threat model
@honua/sdk-js/agent-safety is the deterministic trust boundary between
untrusted agent plan proposals and host-owned effect execution, and
@honua/sdk-js/agent-tools is the bounded runtime-action surface those plans
ultimately drive. Both entrypoints are in the SDK's stable tier (see
docs/decisions/agent-surface-stabilization.md),
so the contracts described here are semver-protected: security reviews may cite
this document knowing a breaking change to any envelope or verification step
requires a major version.
This document enumerates the threats the surface is designed to stop, the
mechanism that stops each one.
Companion reference: docs/agent-safety.md (full API
walkthrough) and docs/nl-map-control.md (the NL layer
that consumes this boundary end to end).
Trust boundaries and assumptions
- The plan proposer is untrusted. Plans, operations, approvals, contexts,
evidence, and receipts all enter as
unknownand are descriptor-snapshotted, bounded (AGENT_SAFETY_HARD_LIMITS), and frozen before any digest or signature check. Accessors are rejected without invocation;Proxyinputs are out of contract. - Key custody and persistence are host-owned.
AgentEnvelopeSigner/AgentEnvelopeVerifierand the atomicAgentApprovalUseConsumerreplay store are host callbacks. The SDK guarantees what is signed and verified, not where keys live. - The SDK never invokes an effect on its own. Dry runs are side-effect
free;
executeAgentPlanStepis the single explicit effect boundary and only runs a host executor after authorization, single-use consumption, and a durable start audit.
Threats and mitigations
1. Envelope forgery
Threat. An attacker fabricates or alters an approval envelope (or the dry run it binds to) to authorize a plan no reviewer signed — forging digests, swapping the approver, or presenting an approval for a different plan/policy.
Mitigation. An approval binds planDigest, policyDigest,
bindingsDigest, and evaluatedAt to one exact dry run, which is itself
recomputed (revalidateDryRun) from the supplied plan and policy — a forged
dry run cannot digest-match. The envelope digest is recomputed over the
canonical unsigned payload, the signer identity (algorithm + key ID) must match
the configured verifier, and the host verifier.verify must return exactly
true. Any mutated field fails integrity-failed or signature-invalid
before an effect is possible.
2. Replay (single-use consumption)
Threat. A valid, signed approval is presented twice — concurrently or sequentially — to run the same approved step more than once (duplicate mutation, publish, job, …).
Mitigation. Approvals are use: "single" per step. Authorization requires
the host AgentApprovalUseConsumer to atomically consume the
(approval digest, step ID, input digest) key and return an authenticated
consumption record (nonce, consumption time, opaque token), which the SDK
immediately re-verifies with the same store. A second consumption attempt
returns nothing and fails policy-denied; the consumption record is bound into
the receipt so post-hoc verification also proves single use. Expiry
(expiresAt, bounded maxClockSkewMs) limits the replay window of any stolen
envelope.
3. Effect-budget bypass
Threat. A plan, approval, or execution result exceeds the reviewed row/byte/step/effect budget — a widened approval, an aggregate that hides a per-step overrun, an oversized operation payload, or an executor returning more data than approved.
Mitigation. dryRunAgentPlan computes a frozen AgentEffectBudgetV1 and
rejects plans over policy ceilings (which are themselves capped by
AGENT_SAFETY_HARD_LIMITS). Approvals may only narrow step limits — widening
fails policy-denied, multi-step narrowing requires explicit stepLimits, and
aggregate approvedRows/approvedBytes must equal the per-step sums. Operation
parameters are bounded by policy byte/node/depth budgets before the replay
store is touched. Execution evidence and receipts exceeding the approved
per-step rows/bytes are refused before signing and on verification.
4. Receipt tampering
Threat. An execution receipt is altered after signing — rows, result digest, approval binding, step ID, or use digest — to misrepresent what was executed or how much data was returned; or a receipt is minted from publicly visible digests without a real authenticated consumption.
Mitigation. issueAgentExecutionReceipt signs the canonical union of
evidence and the plan/policy/bindings/approval digests; the receipt digest is
recomputed on verification and the receipt signer identity must match the
verifier. verifyAgentExecutionReceipt deterministically repeats every
issuance check (budget, binding, consumption authentication via the host
verify callback, approval signature, digest equality) and rejects any
modified field. Receipts are append-only evidence: nothing in the SDK mutates
or re-issues one.
5. Plan-fingerprint mismatch
Threat. The operation a host is about to execute quietly differs from what the reviewer approved: same step ID and tool but a substituted query-plan body, different fields, a different source, or drifted parameters — including a "fingerprint-consistent" forgery where the attacker recomputes content hashes over altered content.
Mitigation. Every plan step carries queryPlan.fingerprint (from
@honua/sdk-js/query-planner), a canonical parametersDigest, and an
inputDigest recomputed from the visible tool/effect/source/query-plan/fields
identity — the claims cannot disagree at parse time. At authorization,
digestAgentOperationInput recomputes the digest from the proposed operation
and requires exact equality with the approved step's digest before the replay
store is consumed; any divergence (id, fingerprint, fields, parameters) fails
integrity-failed. The same binding is revalidated when receipts are issued
and verified. In the NL layer, plan execution additionally re-derives effects
and tool identity from plan content, so recomputed-fingerprint forgeries are
rejected there too.
Adjacent hardening (context, not primary threats)
- Context drift — approvals are re-verified against the current source
bindings (schema/source versions, data mode, provenance freshness); drift
fails
context-mismatch. - Secret exfiltration through tool results — the
/agent-toolsexecutor deeply redacts credential-bearing metadata before results reach a model, and audit events carry pseudonymous digests only. - Hostile host-callback shapes — accessors on executors, stores, and callbacks are rejected without invocation.
What this model does not cover
The SDK does not manage signing keys, persist the replay store or audit log, authenticate approvers, or constrain what a host-authorized executor does with data it legitimately received. Prompt-injection resistance of any LLM driving the surface is out of scope here; the mitigation posture is that a compromised model can only propose plans, and every effect still requires a signed, budgeted, single-use, context-checked approval.