CC3.4 — Considers fraud risk in design and selection of controls
Status: Implemented Owner: Agent #38 (Senior Compliance Lead, SOC 2 + ISO 27001) Last reviewed: 2026-05-28 Next review: 2026-08-28
Trust Services Criteria reference
The entity considers the potential for fraud in the design and selection of controls. Fraud considerations are not bolted on after the control is built — they are inputs into the design decision. The control covers the integration of fraud-risk thinking into control design, the explicit anti-fraud controls (segregation of duties, dual-control, attestation chains), and the cryptographic guarantees that displace human-trust assumptions.
How ZeroAuth meets this control
Fraud-resistance is built into the product architecture, not retrofitted. The two flagship anti-fraud constructions are:
The per-tenant audit hash chain (ADR 0013). audit_events carries previous_hash + event_hash columns; every row is SHA-256(canonical_json(event_data) || previous_hash) per RFC 8785 JSON Canonicalization. The chain is per-tenant so a noisy tenant cannot delay another tenant's chain head. The "what the chain does NOT defend against" section of the ADR explicitly names the residual fraud surfaces (DBA who deletes wholesale + disables drift detector; compromised process that controls writes AND poisons the serialiser; full pause-and-tamper) and routes each to a compensating defence. Implementation: commit a475ed8; integrity-check endpoint commit d634b2d; appendAuditEvent-only-write enforcement commit c09c081.
The daily on-chain anchor (ADR 0014). Each tenant's chain terminal hash is anchored once per day on Base L2 via the AuditAnchor contract (commit d6c6a4e). The contract is write-once for (tenantIdHash, dayUtc) — designed so the bank's auditor can independently verify "this chain existed at this point in time and has not been re-written since" without trusting any ZeroAuth process. The verify-audit-chain.sh helper takes a DB dump and replays the chain row-by-row, then queries Basescan for each AnchorRecord and asserts the terminal-hash match. Zero ZeroAuth runtime dependencies.
The two controls together form a defence-in-depth pair: the in-DB chain catches single-process tampering; the on-chain anchor catches process-and-DBA collusion.
Circuit-version pinning (ADR 0015). A second class of fraud — running a verifier whose vkey does not match the circuit version compiled into the binary — is closed by the boot-time SHA-256 check in src/services/zkp.ts (commit e98d158). The check is non-bypassable (the ADR explicitly rejects a --force flag), so an operator who tries to silently swap a vkey to one that accepts unintended proofs cannot bring the service up.
Tenant isolation (tests/tenant-isolation.test.ts, commit a1bbc47). The source-level guard asserts that every router.<verb> declaration on /v1/* carries the authenticateTenantApiKey middleware. 14 intentionally-public exceptions live in PUBLIC_ROUTE_EXCEPTIONS with ≥ 20-character justifications. A developer who tries to skip the middleware for an "internal endpoint" trips the test before the PR can merge — closing the social-engineering path where someone smuggles an unauthenticated route past code review.
Forbidden biometric-payload guard (tests/biometric-rejection.test.ts, commit c09c081). Source-grep blocks 9 forbidden payload-key patterns (image, template, pixel, depth, frame, raw_face, raw_finger, biometric_data, photo) across req.body / req.query / req.params reads. Runtime defence-in-depth lands with ADR 0016 (commit 76f8d4e) — the zod schema layer adds a .refine() against the same forbidden-key list at parse time, so a generic JSON proxy cannot smuggle a raw-biometric payload past the named-field-read guard.
Demo-bypass removal (audit finding C-1, commit 02e1734). The bypass branch in submitProof accepted any did:zeroauth:demo:* without crypto verification — a deliberate developer-convenience that became a fraud surface in production. The closure removed the branch from src/services/proof-pairing.ts, marked the pairing_demo_mode field on TenantSecurityPolicy as @deprecated, and added tests/proof-pairing.test.ts::"P0 audit finding C-1 closure" as the regression guard. Threat-model row A-27 captures the residual surface.
The compliance-roadmap-led controls that compose with the technical guarantees: quarterly access reviews (D-Q2-12, D-Q3-16, D-Q4-07) limit the access-credential fraud surface; quarterly vendor reviews catch DPA drift; the smart-contract Trail-of-Bits audit (D-Q2-08, D-Q2-09) catches a sophisticated-adversary class of contract-level fraud before mainnet.
Evidence references
- ADR
0013-audit-log-hash-chain.md(commit27ed93c) — chain construction, residual-fraud disclosure. - ADR
0014-on-chain-anchor-cadence.md(commit27ed93c) — independent-verifier defence. - ADR
0015-circuit-version-pinning.md(commit27ed93c) — circuit-key-drift defence; no---forcediscipline. - ADR
0016-zod-input-validation.md(commit76f8d4e) — runtime forbidden-key defence. - Commit
a475ed8— audit hash chain implementation. - Commit
d634b2d—/api/admin/audit-integrityendpoint. - Commit
c09c081—appendAuditEventenforcement + biometric-key grep. - Commit
d6c6a4e—AuditAnchorcontract. - Commit
e98d158— boot-time vkey hash check. - Commit
a1bbc47— source-level cross-tenant guard. - Commit
02e1734— demo-bypass removal.
Open gaps + remediation roadmap
- Quarterly access review v1 — D-Q2-12, target week 26 (2026-11-09), owner Agent #36 + Agent #21.
- External cryptographer audit of
src/services/audit.tscanonicalisation — referenced in ADR 0013 as compensating control for the "compromised process poisons serialiser" scenario. Target Phase 1 week 10 (alongside trusted-setup ceremony). - Trail of Bits / equivalent smart-contract audit — D-Q2-08 + D-Q2-09, target week 24–26.
- Replay-within-window test for A-02 — open gap in
docs/threat_model.md.
Test or audit query
Auditor reads ADR 0013 + ADR 0014 + ADR 0015. Then git log --oneline -- src/services/audit.ts src/services/zkp.ts contracts/AuditAnchor.sol should show commits a475ed8, d634b2d, e98d158, d6c6a4e. cat tests/biometric-rejection.test.ts should reference at least 9 forbidden keys.