We ran the app through OWASP ASVS and the API Top 10.

OWASP ASVS 5.0.0·11 min read·As assessed August 2026

The OWASP Application Security Verification Standard is a list of security requirements an app should meet, level 1 for the basics and level 2 for sensitive applications. We had an AI model check the app against it requirement by requirement, plus the OWASP API Security Top 10. This is the second run, after a quarter in which the sign-in surface grew substantially: passkeys, multiple MFA methods, backup codes, step-up re-authentication. The short version: levels 1 and 2 are met in substance, the new surface opened no exploitable gap, and the broken-access probe came back clean again.

AI-generated assessment

This report was generated by an AI agent reading our codebase against OWASP ASVS 5.0.0. It records a pass or fail for each requirement and the plain-English reason behind it.

It is honest by construction. We asked the model to grade the code against the standard, not to make us look good. This is the same internal assessment we run for ourselves, and we publish the gaps and failures exactly as it found them. Curating it for the public meant removing implementation detail that would help an attacker. It did not mean changing a single verdict or its reasoning.

A human reviewed it before publishing. It is a point-in-time snapshot, last assessed August 2026, not a live mirror of the code.

The verdict

No exploitable findings, no broken access

169
requirements checked
0
exploitable findings
0
critical or high
0
broken-access gaps

Authorization is a clean sweep for the second run in a row: zero findings. Every object you can request is scoped to your organisation at the database layer, and the minimum role for each route is a required field the compiler checks before the route can run. The one planned improvement from the previous run is closed and verified: sessions started through a corporate identity provider now anchor to the provider's own sign-in time. The remaining non-passes are documented, deliberate trade-offs or planned improvements, never an open hole.

By chapter

The ASVS scoreboard

ASVS groups requirements into chapters. Here is where each one landed. “Met in substance” means the level 1 floor is fully met and any level 2 gap is an accepted trade-off or a tracked improvement, not a weakness an attacker can use.

ChapterResultNotes
Encoding & sanitisationMetOutput encoding and input sanitisation in place; no server-side XML parsing to attack.
Validation & business logicMetInput validated against length and type bounds at the boundary; status transitions derived server-side, never accepted from the client.
Web frontend securityMetNonce-based content security policy, no inline script, anti-clickjacking headers, hardened cookie prefixes.
API & web serviceMet in substanceOne accepted redirect behaviour; one transport item delegated to the edge platform.
File handlingMetUploads are type-validated against their magic bytes and scanned by reputation, and downloads fail closed on the scan verdict.
AuthenticationMet in substanceMandatory MFA, now with passkeys and step-up re-authentication; every one-time code and backup code is single-use. Residual items are documented trade-offs, plus one open decision on hardening backup-code storage.
Session managementMet in substanceBounded sessions revoked server-side; federated sessions now anchor to the identity provider's sign-in time. The gaps: a deliberate choice not to keep a per-device session registry, and a written justification of our session lengths against NIST guidance.
AuthorizationMet, zero findingsEvery object access is org-scoped; the required role is checked before every route, on the browser seam and the API-token seam alike.
Self-contained tokensMetClean. The previous run's minor item is closed: session tokens now carry a purpose tag that is checked on every read.
OAuth & OIDCMet in substanceThe relying-party surface passes: PKCE, nonce, signature, issuer match, audience and clock-skew checks, and the callback now verifies the issuer in the authorisation response too. One dismissed item: returning single-sign-on users are matched by verified email within the organisation rather than the provider's opaque subject, a documented design choice.
CryptographyMet in substanceTwo-tier authenticated encryption per organisation, sound at the core. The gaps are governance, not crypto: an algorithm inventory, a written agility statement, a version marker in the stored ciphertext format, and a stricter minimum-strength check on identity-provider signing keys.
Secure communicationMetHTTPS only, TLS handled at the edge, no plaintext egress.
ConfigurationMetNo source-control or build artefacts in the deployed bundle.
Data protectionMet in substanceOne accepted item: a third-party vendor that requires its API key in the URL. Client-side AI chat data is actively cleared on every sign-out and deletion path.
Secure coding & architectureTrackedA documented dependency-remediation timeline and a couple of build-only advisories.
Logging & error handlingMet in substanceStructured logs with secrets scrubbed and every authorization denial logged with who and why. The one gap left is shipping logs off-platform to a separate system.
API Top 10

The API Security Top 10

The same exercise against the OWASP API Security Top 10, the API-specific risk list. “Defended” means the control is in place and verified; “Partial” means a documented residual remains. Eight defended, two partial, zero gaps.

RiskResultControl
Broken object-level access (BOLA)DEFENDEDEvery dynamic route brands the ID and scopes the query to the caller's organisation, sourced from the session token or the API-token record, never the request.
Broken authenticationDEFENDEDNo session means no access; login is throttled per user and per IP; API-token checks run in constant time whether or not the token exists; the billing webhook is signature-verified.
Broken property-level accessDEFENDEDEdits go through a field allowlist; responses select only what's needed; secret keys are never returned.
Unrestricted resource consumptionPARTIALCentral rate limits, request-size caps, and a per-call AI spend cap. Partial: the abuse guard does not yet cover every AI route.
Broken function-level access (BFLA)DEFENDEDA route without a role gate does not compile; denials are logged with the caller's identity; an owner check sits on top where it matters.
Unrestricted access to sensitive flowsDEFENDEDBusiness counters advance atomically, repeated API calls can be made idempotent with a client key, and sensitive account actions re-verify the caller first.
Server-side request forgery (SSRF)PARTIALUpstream hosts are fixed, private address ranges are blocked, every outbound call has a deadline. Partial: one vendor requires its key in the URL, and identity-provider discovery necessarily fetches an owner-supplied address; both accepted with reasoning.
Security misconfigurationDEFENDEDA full security-header bundle on every response; info-disclosure headers stripped at the edge; no wildcard cross-origin access.
Improper inventory managementDEFENDEDA versioned API namespace, a published machine-readable spec, downloadable agent docs, and a documented route table.
Unsafe consumption of third-party dataDEFENDEDThe billing webhook is signature-checked, AI output is sanitised before display, identity tokens are validated against the provider's published keys, and no raw SQL.
The probe

The broken-access test

Broken object-level access is the most common serious API flaw: asking for someone else's record by guessing its ID and getting it. The assessment sampled 17 different object paths across 16 kinds of data, on both ways into the app (browser session and API token), biased toward routes that didn't exist at the last run, and tried to reach across the tenant boundary on each.

Result

Zero scoping gaps. Every client-supplied ID is checked against the caller's organisation, which comes from the signed session or the API-token record and never from the request. A guessed ID from another organisation returns nothing.

The good part

The strongest passes

  • Compile-time tenant boundary. The identifier types make a cross-tenant call a compile error, backed by uniform org-scoping at the database and a required role check before every route.
  • Single-use holds on every factor type. An authenticator code cannot be replayed inside its own validity window, a backup code is consumed with a race-safe conditional write, and a passkey challenge is claimed before it is verified.
  • Timing-equal secret checks. A request with an unknown API token and one with a wrong secret take the same constant-time path, so response timing reveals nothing about what exists. Password checks behave the same way.
  • Per-organisation authenticated encryption. A master key wraps a separate random key for each organisation, and every field and file is encrypted under its org's key with integrity protection.
  • Search without decryption. Each organisation gets its own one-way search key, so the same word produces a different, irreversible token in every organisation and searching never decrypts a row.
  • Full OAuth relying-party hygiene. PKCE, state and nonce replay checks, signature verification, exact issuer match on both the discovery document and the authorisation response, audience and clock-skew validation, and a verified-email gate.
  • Fail-closed session revocation. Sessions run on an idle window plus a hard cap, are revoked server-side on password change or sign-out, and are rejected outright if the revocation store can't be reached.
The honest part

Where it doesn't fully pass yet

None of these is exploitable today. They are either deliberate trade-offs we have weighed and accepted, or improvements we have planned. Most of what this run added to the list is written work the checklist forced into view, which is exactly what an external standard is for.

  • Crypto governance paperwork. The encryption is sound; the written record around it is thinner. An inventory of the algorithms in use, a formal statement of how we would migrate off one, and a version marker in the stored ciphertext format are all still to write.
  • Session-length justification. Our session lengths are deliberate and documented, but the doc never argues them against the NIST guidance the standard points at. One paragraph of honest reasoning to add.
  • Backup-code storage. Backup codes are stored keyed and hashed, but not with the slow password-grade hash the standard prescribes for short codes. We owe this one a decision, upgrade the hash or record a formal acceptance, and it was flagged last run too. Saying that out loud is the point of publishing these.
  • Off-platform log shipping. Logs live in our platform's log store and are not yet shipped to a separate, breach-resilient system. Planned.
  • Dependency hygiene. A documented remediation timeline for dependencies, plus a couple of build-only advisories that don't ship to production.
  • Accepted trade-offs. A few items are deliberate: password reset by email code (sign-in still forces MFA), one vendor that mandates its API key in the URL, and no per-device session registry. Each is documented with the reasoning.
The method

How it was checked

Four agents worked in parallel from the official OWASP requirements list, splitting identity and sessions, tokens and cryptography, authorization with the API Top 10 and the broken-access probe, and logging plus the platform chapters. A pass required evidence in the source, not an assumption. The orchestrating model then re-verified every fail, every partial, and every verdict that changed since the previous run directly at the source, and re-read a sceptic's sample of the passes before anything was recorded.

How this was made

Curated from our internal report for public release. We removed implementation detail that would help an attacker, generalised file references to the controls they point at, and dropped internal tracking IDs. We did not change a single verdict or its reasoning. When we re-run the internal assessment, we refresh this page by hand.

This is the product the report graded.

A purpose-built security register with per-org encryption, mandatory MFA, and EU data residency. Free tier, no card.