Veefore docs

Threat model

Attacker goals, the mechanism that refuses each one, and the residual risk that remains.

Written as goals an attacker would have, because that is how the defences were chosen. Every case has a corresponding test in tests/security — 49 of them. A threat model without tests is a wish list.

#Impersonate an agent

Goal Refused by
Use a stolen agent id Ids are not credentials. A signed assertion over the private key is required
Replay a captured assertion Single-use nonce → NONCE_REPLAYED
Use an expired assertion Short exp, plus a timestamp window → TIMESTAMP_OUT_OF_WINDOW
Replay an assertion against a different environment aud is bound and compared exactly
Use a key after rotation Generation counter → IDENTITY_GENERATION_STALE
Use a key after revocation AGENT_IDENTITY_REVOKED. Terminal
Forge a passport Platform Ed25519 signature over canonical JSON
Present a stale passport The gateway re-resolves live authority; it never authorizes from a passport

Residual risk. An attacker who obtains the private key and the agent id can act as that agent until it is revoked. The mitigations are rotation, short-lived sessions, and the fact that the agent's authority is bounded — so what they get is the agent's bounded authority, not open access.

veefore doctor checks local key file permissions; a key readable by another process on the host is a key that process can act with.

#Escalate authority

Goal Refused by
Delegate more than you hold DELEGATION_ESCALATION at creation. Refused, not clamped
Widen an existing delegation Same invariant on PATCH
Extend an expiry past the parent's Same
Exploit a long chain Depth bounded by max_depth; narrowest value wins at every dimension
Use a revoked parent's grant Revocation cascades at every depth, immediately
Call a tool without the capability CAPABILITY_NOT_GRANTED
Call a tool you hold the capability for but are not authorized for TOOL_NOT_AUTHORIZED
Gain reach by registering a new tool Registration grants nothing. Authorization is a separate step
Gain reach via MCP discovery A discovered tool is unauthorized until a human authorizes it
Obtain a high-impact permission through a wildcard role HIGH_IMPACT_PERMISSIONS must appear explicitly
Use an old session for an irreversible operation STEP_UP_PERMISSIONS require fresh re-authentication

Residual risk. An agent granted too much authority in the first place is operating within its grant. Veefore bounds and records; it cannot know your intent. Review delegations monthly and grant the narrowest ceiling that works.

#Steal a credential

Goal Refused by
Read a credential from the API No endpoint returns material. Metadata only
Extract it from an agent's context The agent never holds it. Only short-lived, scoped leases
Find it in logs Redaction applied on ingest, not on output
Find it in the audit trail Leases recorded by reference, never by value
Find it in an error message Messages never contain secret values
Use a lease after rotation Rotation invalidates every outstanding lease
Get a lease issued for a blocked action Brokering is stage 10, after every refusal
Find one committed to source npm run quality:audit fails the build

Residual risk. A leaked lease is usable within its short lifetime for the single action it was scoped to. A compromise of VEEFORE_DATA_ENCRYPTION_KEY and the database would expose stored material — which is why that key belongs in a secret manager and not in the database.

#Reach another tenant's data

Goal Refused by
Pass another organization's resource id Repository layer requires a tenant scope → TENANT_MISMATCH
Exploit a query that forgot its scope PostgreSQL row-level security, as an independent second layer
Use scope headers you have no access to Scope is validated against the session
Enumerate ids TENANT_MISMATCH rather than 404, so the attempt is distinguishable in audit

Residual risk. A bug in both layers simultaneously. The two are independent by design — one in application code, one in the database — so a single mistake is not sufficient. Enable DATABASE_ENABLE_RLS in production. → Tenant isolation

#Make the agent do something harmful

This is the category people care most about, and the honest answer is a reduction in reward rather than prevention.

Goal Refused by
Inject a prompt to steal a credential There is nothing to steal
Inject a prompt to exceed a ceiling AUTHORITY_EXCEEDED at stage 6
Inject a prompt to call an unauthorized tool TOOL_NOT_AUTHORIZED at stage 5
Inject a prompt to reach an unexpected host DESTINATION_BLOCKED at the egress boundary
Inject a prompt to drop a table Starter policies block DELETE, DROP, TRUNCATE
Talk the agent past a limit Limits are server-side numbers the agent cannot see
Convince the agent it is authorized Belief is irrelevant. The gateway decides

Veefore does not prevent prompt injection

It makes injection much less rewarding. The agent has no credential to exfiltrate, and anything it is talked into attempting still runs the full twelve-stage pipeline against the same authority and the same policy.

Authorization in a system prompt is not authorization. "You may only refund up to ₹1,000" is an instruction, and instructions are negotiable. Put the ceiling in a delegation. → The boundary

Residual risk. An agent authorized to do something harmful, doing it. The value is bounded authority, a recorded decision and a known blast radius. Narrow grants are the mitigation.

#Evade the audit trail

Goal Refused by
Alter one event Keyed hash chain; the break is detectable and localised
Delete an event Same
Act without being recorded Every pipeline run writes an action record
Export evidence unnoticed Export requires a reason and is itself an audit event
Shorten retention quietly Step-up gated, CRITICAL audit event
Alter an exported file Exports are watermarked and hashed

Residual risk. An attacker with database write access and VEEFORE_AUDIT_CHAIN_SECRET could rewrite the chain consistently. Keep the secret out of the database, restrict write access, and ship events to an append-only sink you control separately. → Audit integrity

#Use availability as an attack

Goal Refused by
Make policy unreachable so everything is allowed Fail-closed. POLICY_SERVICE_UNAVAILABLE, actions refused
Make identity unreachable Same
Overwhelm the gateway to slip a request through Rate limiting; refusal under pressure, not permission
Exhaust capacity through one broken downstream Per-tool circuit breaker after 5 failures
Flood with requests Velocity limits are themselves a policy decision

This is why fail-closed is not negotiable

Under fail-open, every denial-of-service becomes a privilege escalation — and making a service unreachable is far easier than defeating its policy. The cheapest attack would become an attack on availability rather than on correctness. → Fail closed

Residual risk. Protected actions stop during an outage. The mitigation is redundancy, not a bypass.

#Attack the egress path

Goal Refused by
Point a tool at an internal host The tool's own destination_allowlist, checked again at egress
Use a redirect to reach a non-allowlisted host redirect: 'error'. Redirects are refused, not followed
Exfiltrate over plaintext HTTPS required unless the host is loopback
Hold a connection open to exhaust the gateway 15-second egress timeout, plus the circuit breaker

The redirect refusal is worth calling out: following a redirect is how an allowlisted host becomes a request to a host that was never allowlisted. That is server-side request forgery with extra steps, and the only safe handling is to refuse.

#Attack a human session

Goal Refused by
Use a stolen session for an irreversible action Step-up required at the moment of use
Use an idle session SESSION_IDLE_TIMEOUT_SECONDS
Brute-force a password MAX_LOGIN_ATTEMPTS and lockout
Reach the API from an unexpected network IP allow/deny rules → NETWORK_RESTRICTED
Approve from an unattended browser requireStepUp on the approval rule

#Out of scope for this model

Physical access to the database host. Standard infrastructure security.

A compromised Veefore deployment. If an attacker controls the gateway process, they control authorization. Protect it as you would any critical service.

Your downstream's own security. Veefore brokering a credential does not make an unauthenticated API safe.

Model behaviour. Veefore bounds what an agent may do. It does not evaluate whether a model's reasoning is sound.

#Verifying this page

bash
npm run test:security   # 49 cases
npm run test:chaos      # 13 cases, fail-closed and recovery
npm run smoke:gateway   # replay refusal, enforcement, revocation, over real HTTP

Identity, authority, policy and enforcement for autonomous AI agents.