Skip to content

Latest commit

 

History

History
166 lines (131 loc) · 25.8 KB

File metadata and controls

166 lines (131 loc) · 25.8 KB

PEAC Protocol threat model

Consolidated threat model for the wire format, the open-source reference verifier, the MCP server, and the published Layer 4 adapters. Each threat below lists the mitigation and a test path that exercises it; the companion verifier scripts/verify-trust-artifacts.mjs fails CI if any referenced test path does not exist or if any threat row lacks a test link.

Scope

In scope:

  • Wire format (typ: interaction-record+jwt, Wire 0.2; peac-receipt/0.1, Wire 0.1; archival peac.receipt/0.9).
  • Signature verification (Ed25519, JWS Compact Serialization, JCS).
  • Issuer-config and JWKS resolution.
  • Reference verifier (apps/api).
  • MCP server (@peac/mcp-server) stdio and Streamable HTTP transports.
  • Layer 4 commerce mapper boundary (@peac/adapter-core assertExplicitFinality).
  • Cross-language parity (packages/schema and sdks/go).

Out of scope:

  • Managed Hosted Verify (operated separately under its own threat model).
  • Customer-side key custody (bring-your-own-key; see Key custody and tenancy).
  • Transport-level confidentiality beyond what TLS and RFC 9421 provide.
  • Application-level business logic layered on top of PEAC records.

Trust boundaries

Boundary Assumption
Record issuer ↔ record verifier Untrusted over the wire; trust is established by the issuer's JWKS binding
Reference verifier ↔ upstream JWKS Untrusted network; SSRF-safe fetch + private-range block
Caller ↔ @peac/protocol public API Trusted process boundary; caller supplies keys and fixtures
MCP client ↔ MCP server Session-isolated per client; no shared mutable state between clients
Layer 4 mapper ↔ upstream artifact Upstream state is never synthesized into finality; see commerce-finality guard

Threat catalog

Each row links to a test file that exercises the mitigation. CI enforces that every link resolves to a tracked path.

Wire format and signature

ID Threat Mitigation Test coverage
T-WIRE-01 Forged signature Ed25519 verify (RFC 8032); JWS Compact Serialization (RFC 7515) packages/crypto/tests/jws.test.ts
T-WIRE-02 JOSE header abuse (jwk/x5c/x5u/jku) Embedded-key forms rejected on verify packages/crypto/__tests__/jws-wire-02.test.ts
T-WIRE-03 Critical-extension abuse (crit / b64:false / zip) Disallowed at the JWS layer packages/crypto/__tests__/jws.property.test.ts
T-WIRE-04 Wire-version confusion (0.1 ↔ 0.2 cross-claim) typ header drives dispatch; coherence enforced at verify packages/protocol/__tests__/strictness.property.test.ts
T-WIRE-05 Receipt-ref tampering receipt_ref = sha256(receipt_jws) verified at extraction packages/schema/__tests__/carrier.test.ts
T-WIRE-06 Replay attack jti uniqueness; iat / nbf / exp time bounds; verifier-side replay cache packages/protocol/__tests__/verify-local-order.test.ts
T-WIRE-07 Canonical-JSON divergence (JCS RFC 8785) Golden vectors; property tests; cross-language parity packages/crypto/tests/jcs.test.ts, packages/net/node/tests/jcs-property.test.ts
T-WIRE-08 Algorithm confusion / downgrade Ed25519 only; no alg negotiation packages/crypto/tests/golden-vectors.test.ts
T-WIRE-09 Policy-binding forgery (policy claim not bound to issuance) JCS-based policy digest + three-state policy-binding result packages/protocol/__tests__/policy-binding.test.ts

Issuer and JWKS resolution

ID Threat Mitigation Test coverage
T-RES-01 SSRF via issuer-config / JWKS fetch HTTPS only; private, loopback, and reserved-range block; IDNA / bracket / IPv4-in-IPv6 expansion blocked packages/net/node/tests/safe-fetch.test.ts, packages/net/node/tests/ssrf-expansion.test.ts
T-RES-02 Slowloris / unbounded fetch time Explicit timeout cap on every network-bearing path packages/jwks-cache/tests/resolver.test.ts
T-RES-03 JWKS cache poisoning / kid substitution Bounded LRU keyed per issuer; kid retention with reuse detection packages/jwks-cache/tests/security.test.ts, packages/jwks-cache/tests/cache.test.ts
T-RES-04 Redirect-chain attack (cross-origin redirect to private range) Redirect policy bounded; redirects to blocked ranges rejected packages/net/node/tests/safe-fetch.test.ts
T-RES-05 receipt_url fetch amplification Semaphore, per-tenant quota, fetch timeout, SSRF-safe packages/net/node/tests/receipt-url-middleware.test.ts
T-RES-06 Reference-verifier discovery ambient fetch Discovery constrained to verified resolver paths; no ambient pointer fetch packages/protocol/tests/pointer-fetch.test.ts, packages/protocol/tests/jwks-resolver.test.ts

Verifier resource control

ID Threat Mitigation Test coverage
T-VRFY-01 Oversized record DoS Receipt, per-extension-group, total-extension, nesting-depth, and member-count caps enforced packages/schema/__tests__/constraints.test.ts, packages/schema/__tests__/byte-budget-enforcement.test.ts
T-VRFY-02 Kernel-constraint bypass (pre-signing path) validateKernelConstraints() enforced in issue() before signing and on verify packages/protocol/tests/issue-constraints.test.ts, packages/protocol/tests/verify-constraints.test.ts
T-VRFY-03 Issuance path calls network (no-network invariant) Issuance MUST NOT perform any network I/O tests/security/no-fetch-audit.test.ts
T-VRFY-04 Wire 0.2 issuance byte-identity drift Property test over canonical JCS + JWS construction packages/protocol/__tests__/issue-wire-02.test.ts

Shadow-mode telemetry (internal-only)

v0.13.2 adds an internal-only shadow-mode diagnostic foundation in apps/api for cross-implementation pointer-fetch parity observation. The foundation is governed by PEAC_INTERNAL_SHADOW_RESOLVER and PEAC_INTERNAL_SHADOW_BUFFER_SIZE (see docs/STABILITY-CONTRACT.md "Internal-only flags"). Diagnostic prose lives in docs/diagnostics/SHADOW-MISMATCHES.md.

ID Threat Mitigation Test coverage
T-SHDW-01 Raw URL path / query / fragment leakage into mismatch sink Normalization layer surfaces only public response metadata; redaction-discipline assertions on every recorded entry apps/api/tests/parity-public-root-smoke.test.ts
T-SHDW-02 Bearer / cookie / private-key material in sink entries Bounded summary fields; classifier emits class enum + numeric counters only; per-field length caps apps/api/tests/parity-public-root-smoke.test.ts
T-SHDW-03 Mismatch sink memory exhaustion Fixed-capacity ring buffer; default 1024 entries; env-clamped to [64, 16384]; in-memory only (no file writes, no network egress) apps/api/tests/shadow-mismatch-sink.test.ts
T-SHDW-04 Per-entry size unbounded ~512-byte JSON-stringified cap per entry with progressive degradation (clamp -> drop excerpts -> placeholder code -> minimal entry) apps/api/tests/shadow-mismatch-sink.test.ts, apps/api/tests/parity-public-root-smoke.test.ts
T-SHDW-05 Shadow path executes when flag unset Lazy module import gated by PEAC_INTERNAL_SHADOW_RESOLVER === '1'; default OFF; the workspace-private resolver composition layer is never loaded otherwise apps/api/tests/shadow-resolver.boundary.test.ts
T-SHDW-06 Cross-implementation digest disagreement (silent drift) Pure-function parity verdict tags parity_digest_mismatch; treated as stop-the-line if observed in production apps/api/tests/shadow-classify.test.ts, apps/api/tests/shadow-execute.test.ts

MCP server

ID Threat Mitigation Test coverage
T-MCP-01 Cross-client state leak (Streamable HTTP) Session-isolated McpServer + transport per client packages/mcp-server/tests/http/session-manager.test.ts, packages/mcp-server/tests/http/http-transport.test.ts
T-MCP-02 Static-policy bypass (runtime policy mutation) Static policy loaded at startup; immutable at runtime packages/mcp-server/tests/infra/policy.test.ts
T-MCP-03 Path-traversal via handler input Path-safety validation on every file-bearing handler input packages/mcp-server/tests/infra/path-safety.test.ts
T-MCP-04 Stdout framing bypass (stdio transport) Line-buffered stdout fence packages/mcp-server/tests/security/stdout-fence.test.ts
T-MCP-05 Evidence-carrier size overflow in _meta Transport-binding size caps; 64 KB embed for MCP / A2A / UCP packages/mcp-server/tests/integration/e2e-smoke.test.ts

Commerce mapper boundary

ID Threat Mitigation Test coverage
T-CMRC-01 Mapper synthesizes finality from non-payment artifacts assertExplicitFinality boundary guard; stable code commerce.finality_synthesis_blocked packages/adapters/core/tests/finality.test.ts, packages/adapters/core/tests/finality-fixtures.test.ts

Cross-language parity

ID Threat Mitigation Test coverage
T-PARITY-01 TS / Go wire-output divergence Shared JCS golden vectors; claim parity property tests tests/parity/core-claims.test.ts, specs/conformance/fixtures/go-interaction-record/jcs-golden-vectors.json

Mitigation gaps (acknowledged)

These mitigations are in effect but have scheduled follow-ups for a future release. The stability contract and security operations describe the current behavior; the scheduled work is planning scope, not a current gap in shipped behavior.

  • Mutation-testing baseline (Stryker for TypeScript; go-mutesting for Go).
  • Error-code emission audit (classify unused codes in specs/kernel/errors.json).
  • Verifier-policy extraction from @peac/kernel into a verifier-owned surface.
  • Resource-limit invariant table with per-row implementation, test, and baseline references.

CLI execution and lifecycle observation surfaces

The CLI command-execution and observational lifecycle record surfaces have shipped. Their security contract is enforced by the rules below.

ID Threat Mitigation Test coverage
T-CLI-01 Raw command, stream, or argument secret capture Hash/redact defaults for argv/stdin/stdout/stderr; explicit raw-capture acknowledgement; bounded byte ceilings; secret-scan guard on raw samples packages/cli/tests/secret-scan.test.ts, packages/cli/tests/capture.test.ts
T-CLI-02 Shell ambiguity or hidden shell expansion shell: false default; --shell-mode required to acknowledge a shell binary; command after -- spawned as supplied packages/cli/tests/observe-command.test.ts, packages/cli/tests/record-command.test.ts
T-CLI-03 Environment-variable leakage Deny-by-default env capture; explicit --env-allow allowlist; hashed values by default; raw env requires double opt-in packages/cli/tests/observe-command.test.ts, packages/cli/tests/capture.test.ts
T-LIFE-01 Lifecycle record overclaims decision truth Caller-reported event model; opaque-reference grammar; no inline scoring/finality synthesis; closed enum of forbidden top-level keys packages/schema/__tests__/extensions/lifecycle-observation.test.ts, packages/schema/__tests__/extensions/lifecycle-observation-shape.test.ts
T-LIFE-02 PEAC mistaken for evaluator/approver/orchestrator Profile boundary: PEAC issues records; upstream systems evaluate, approve, schedule, transition, or orchestrate docs/specs/LIFECYCLE-OBSERVATION-PROFILE.md §8 (orchestrator boundary, normative)

Security defaults summary:

  • No raw secret capture by default. argv, stdin, stdout, stderr default to hash/redact modes; raw capture requires --capture-mode raw AND --unsafe-allow-raw-capture (double opt-in).
  • Environment-variable allowlist plus value hashing. No blanket environment dump. Only explicitly-listed variables enter the record, and even those are hashed by default. Raw env requires --env-mode raw AND --unsafe-allow-raw-env.
  • Explicit shell mode. Shell-binary detected without --shell-mode is a hard fail. Hidden shell-expansion ambiguity is rejected.
  • Bounded byte ceilings on command capture. argv bytes, stream bytes, and environment-variable reference counts all carry documented upper bounds. Exceeding a bound truncates or hashes; it never silently drops.
  • Lifecycle records are observational-only. Approval, evaluation, experiment, and workflow records describe what another system attested. They never imply PEAC made the decision, scored the runtime, enforced the policy, or determined payment finality.

Related documents