Security

Security standards: a self-assessment

How Counterseal's controls line up with five OWASP standards and lists, with what is met, what is partly met and what is not, in our own words.

Self-assessed. We read our own code and tests against each standard. Nobody else has audited this, Counterseal is not certified against any of these, and OWASP does not certify anyone against them. Where a row says "met", it names the test that checks it, in the source repository. The security page describes each control, and the threat model in the repository explains why.

Assessed 9 October 2026, against the code on branch feat/app-trust

OWASP ASVS 5.0.0 (May 2025): Level 2, and Level 3 where we meet it

ASVS has 17 chapters. We target Level 2 for the whole service and name the Level 3 requirements we also meet. Chapters that do not apply say why.

ChapterStatusHow
V1 Encoding and SanitizationMet (L2)Every SQL statement is parameterised; no page writes HTML from text (no innerHTML, enforced by Trusted Types and a CI check); text from agents shown to people has control, invisible and direction characters made visible. Tests: bypass.test.js, approvals.test.js.
V2 Validation and Business LogicMet (L2)Strict JSON bodies with size caps read while streaming, unknown fields refused, fixed vocabularies; per-account ceilings on everything an account can create; limits on held requests per token and per account against approval fatigue. Tests: second-pass.test.js, hardening.test.js.
V3 Web Frontend SecurityMet (L2); L3 items on headers metA strict Content Security Policy with require-trusted-types-for 'script', no third-party code, HSTS, COOP, CORP, frame-ancestors 'none', __Host- cookies with SameSite=Strict. The service worker caches only the app's own files and never the API. Tests: second-pass.test.js, app-shell.test.js.
V4 API and Web ServiceMet (L2)JSON only, with the content type checked; methods per route; CORS only on the public log's read endpoints; CSRF: an Origin equal to the one host plus a custom header on every browser write. Tests: domain.test.js, app-trust.test.js.
V5 File HandlingNot applicableNothing is uploaded. Downloads (receipts, agent keys, the data export, the evidence pack) are made in your browser.
V6 AuthenticationMet (L2). L3 6.3.3 met with a device-bound passkey or a security keyPasskeys only (WebAuthn, user verification required, origin and RP ID checked, single-use challenges); no passwords exist, so there is no weaker path. Synced passkeys meet L2; L3 asks for a hardware-based factor. Sign-in and approval limits; new command line sign-ins and new passkeys alert your devices. Tests: leash.test.js, cli-signin.test.js.
V7 Session ManagementMet (L2), except 7.5.2 partly. L3 7.5.3 metReference tokens of 256 random bits, stored as hashes; 12 hours at most on the web and 7 days for a command line; a web session also ends after an hour without an action of yours (added on this branch); logout deletes the session. Every sensitive action asks for your passkey again (7.5.3). Command line sessions are listed and can be revoked with everything they made; other browser sessions are not listed yet, but removing a passkey signs them all out. Tests: app-trust.test.js, cli-signin.test.js.
V8 AuthorizationMet (L2)Every query is scoped to the account; team roles are checked on the server for every request; a passkey proves presence, not authority. Tests: team.test.js, leash.test.js.
V9 Self-contained TokensMet where usedSessions and agent tokens are reference tokens, not JWTs. Agent request signatures (RFC 9421) cover the method, URL, body digest and content type, within 5 minutes, each nonce once. Tests: leash.test.js, joints.test.js.
V10 OAuth and OIDCNot applicableCounterseal is not an OAuth client, server or identity provider.
V11 CryptographyMet (L2)AES-256-GCM per vaulted key with its own data key, wrapped by a master key and bound to its row; Ed25519 checkpoints; SHA-256; the platform's random generator. The master key rotates without losing a stored key: only the data keys are wrapped again, the secrets are never decrypted for it (procedure in docs/KEY_ROTATION.md, test key-rotation.test.js). It has not been run on the live service yet.
V12 Secure CommunicationMet (L2)HTTPS only, with HSTS for two years on every subdomain (preload asked for; the parent domain is not on the preload list yet); calls to providers go only to their fixed HTTPS hosts (Shopify: to a strictly checked store address); redirects are never followed.
V13 ConfigurationMet (L2)Secrets live in the platform's secret store, never in the repository; zero runtime dependencies; request logs off; a generic error to clients.
V14 Data ProtectionMet (L2)No secret in a URL (one-time links carry their token in the fragment and POST bodies); Cache-Control: no-store on every API answer; data minimised and listed in the privacy policy; an owner can download all of it and choose how long closed holds are kept; account deletion leaves no row that names the account (tested). Tests: app-trust.test.js.
V15 Secure Coding and ArchitectureMet (L2)A threat model; zero runtime dependencies; GitHub Actions pinned by commit; on this branch, an SBOM and npm provenance in the publish workflow.
V16 Security Logging and Error HandlingPartly metEvery decision and every security change is in your hash-chained audit log, which you can export and verify. Security events (bad tokens, CSRF, replays, limits) go to a live log stream with no personal data, but are not stored, by choice (request logs are off for privacy); that falls short of keeping security logs for later investigation.
V17 WebRTCNot applicableNo WebRTC.

OWASP Top 10:2025

RiskWhat Counterseal does
A01 Broken Access ControlAccount-scoped queries, server-side roles, CSRF checks on the one host, the two-person seal for held actions.
A02 Security MisconfigurationThe same security headers on every page, checked by a test against the Worker's own list; request logs off; secrets only in the platform's store.
A03 Software Supply Chain FailuresZero runtime dependencies in the Worker, CLI and SDK; actions pinned by commit; an SBOM and provenance for the published CLI (this branch).
A04 Cryptographic FailuresPer-secret AES-256-GCM with additional data, Ed25519, SHA-256, WebCrypto only. The master key rotates by a tested procedure (docs/KEY_ROTATION.md).
A05 InjectionParameterised SQL; Trusted Types; strict parsers for the bodies the irreversible map reads.
A06 Insecure DesignA threat model; irreversible actions are held outside the model; dangerous switches need a passkey, never a command line session.
A07 Authentication FailuresPasskeys only; device-code phishing defences for command line sign-in; idle and absolute session limits.
A08 Software or Data Integrity FailuresThe hash-chained audit log, the public Merkle log with signed checkpoints, approvals bound to one exact request and used once.
A09 Security Logging and Alerting FailuresAlerts on your devices for held calls, new sign-ins, new passkeys and team changes; the audit log. Security events are not stored (see V16).
A10 Mishandling of Exceptional ConditionsFails closed: an unreadable request is held, an unreachable server makes the guard deny, and a full or broken public log never blocks a decision, which is still written to your audit log.

OWASP API Security Top 10 2023

RiskWhat Counterseal does
API1 Broken Object Level AuthorizationEvery object is looked up with its account; another account's id gets 404 (tested).
API2 Broken AuthenticationPasskeys, hashed bearer tokens, short device codes with limits.
API3 Broken Object Property Level AuthorizationAnswers name their fields; no secret column is ever returned (the data export test checks every secret is absent).
API4 Unrestricted Resource ConsumptionRate limits on every route, size caps, per-account ceilings, a breaker per token, Workers Free budgets tested (D1 queries and CPU).
API5 Broken Function Level AuthorizationRoles per route; passkey-only routes refuse a command line session.
API6 Unrestricted Access to Sensitive Business FlowsThe irreversible map, money caps, the two-person seal, limits on how many holds can wait.
API7 Server Side Request ForgeryFixed upstream hosts, push services from an allow list, no redirects, a strictly checked store address.
API8 Security MisconfigurationAs A02.
API9 Improper Inventory ManagementEvery route is in one table in server/src/index.js; the protocol is documented; the map is versioned.
API10 Unsafe Consumption of APIsUpstream answers cannot act on a browser at our origin (their CORS, cookies and policies are dropped); upstream data read for money caps is parsed strictly.

OWASP Top 10 for LLM Applications 2025

Counterseal runs no model. It sits between AI agents and the APIs they call, so the risks that apply are the ones about what an agent can do.

RiskWhat Counterseal does
LLM01 Prompt InjectionA hold does not depend on what the model was told: an irreversible call waits for a person whatever the prompt said. Your deny reason goes back to the agent as data.
LLM02 Sensitive Information DisclosureThe agent never holds the real key, so a model that leaks its context leaks only a revocable, scoped token.
LLM03 Supply ChainAs A03, for the CLI and MCP server the agent runs.
LLM05 Improper Output HandlingWhat the agent sends is parsed strictly before it is allowed; anything ambiguous is held; hidden characters are made visible to the approver.
LLM06 Excessive AgencyThe reason Counterseal exists: scoped tokens, irreversible calls held for a passkey, money caps, a breaker and Freeze.
LLM10 Unbounded ConsumptionRate limits and the breaker cap calls through Counterseal. They do not cap the model's own token spend.
LLM04, LLM07, LLM08, LLM09Not applicable: Counterseal trains no model, has no system prompt, stores no embeddings and generates no text.

OWASP Top 10 for Agentic Applications 2026

Published by the OWASP GenAI Security Project on 9 December 2025.

RiskWhat Counterseal does
ASI01 Agent Goal HijackA hijacked agent still cannot take an irreversible action through Counterseal without a person's passkey.
ASI02 Tool Misuse and ExploitationThe irreversible map (10 APIs) and the coding-agent guard's shell map hold the dangerous calls of each tool.
ASI03 Identity and Privilege AbuseScoped, expiring tokens instead of real keys; agent keys so a stolen token alone is useless; command line sessions cannot approve.
ASI04 Agentic Supply Chain VulnerabilitiesZero dependencies and provenance for our own CLI. The guard can ask for approval of MCP tool calls; checking third-party tool definitions is not in this branch.
ASI05 Unexpected Code ExecutionThe guard holds destructive shell commands until approved. It runs on the agent's machine: a seatbelt, not a sandbox.
ASI06 Memory and Context PoisoningOut of scope: Counterseal keeps no agent memory. A poisoned agent is still held at the irreversible step.
ASI07 Insecure Inter-Agent CommunicationAgent-to-broker requests can be signed (RFC 9421) and replays are refused. Agent-to-agent traffic does not pass through Counterseal.
ASI08 Cascading FailuresA breaker per token, Freeze for every token at once, rate limits, and fail-closed defaults.
ASI09 Human-Agent Trust ExploitationThe approver sees the exact request or command with hidden characters made visible; limits on waiting holds and alerts against approval fatigue; device-code phishing defences; the two-person seal.
ASI10 Rogue AgentsFreeze, revocation of tokens and keys, the audit log, and public receipts anyone can verify.

What is not met yet

Fixed while writing this: a web session now ends after an hour without an action (V7 7.3.1); deleting an account now also removes rate limit counters that name it (V14); the app's offline copy is tested never to hold API data (V3, V14).

Sources (read 9 October 2026)