Finding — surviving cross-examination confirmed · 03:42
Probatum
Authentication bypass on account deletion
services/auth/verify.py · lines 184–207 · severity high
Reasoning The delete handler short-circuits verification when token.kind == "admin", trusting the claim before verify_signature() runs. Any signed-looking blob with that claim passes. Reproduction POST /v1/accounts/{id}/delete with a forged token of kind admin — see repro script in the report.
Critique log — “Refutation attempted four ways: mTLS, WAF rule, pre-handler middleware, version history. None are invoked on the delete path. Fault confirmed.”
Probatum
Cross-tenant invoice access via warm cache
services/billing/invoices.py · lines 42–71 · severity high
Reasoning Invoice lookup checks ownership only on the DB path. Cache hits skip the check entirely — a warmed cache exposes any invoice by incrementing the id. Reproduction Request /invoices/{your-id} to warm the cache, then request /invoices/{neighbor-id}. The second call returns without an ownership assertion.
Critique log — “Considered: signed URL, tenant-scoped cache key, gateway-level ACL. The cache key is plain (id) and the ACL lives below the cache. Exploit holds.”
Refutatum
SSRF via unrestricted URL fetch — not exploitable
services/preview/fetch.py · lines 88–130 · verdict refuted
Hypothesis The preview endpoint appeared to accept arbitrary URLs and forward them server-side, suggesting SSRF into the internal metadata service. Why it fails Outbound requests are routed through an egress proxy that blocks RFC1918 ranges, 169.254.*, and the metadata IP before the socket opens. The check runs before DNS resolution, so rebinding is closed too.
Critique log — “Attempted four vectors: direct IP, hostname to internal, DNS rebinding, redirect chain. Egress proxy rejects all of them at L4. No exploit.”
Probatum
Privilege escalation via mass-assignment on member update
services/workspace/members.py · lines 204–238 · severity critical
Reasoning The member-update handler spreads the request body into the model without a field allowlist. The role field is writable even though the UI never exposes it — any member can PATCH themselves to owner. Reproduction As a regular member, PATCH your own membership with {"role":"owner"}. The server returns 200 and the role is persisted.
Critique log — “Looked for: middleware scrubbing, serializer allowlist, audit-log trigger. None reject the role write. Confirmed on staging replica.”
Refutatum
Second-order XSS via markdown cache — not exploitable
services/render/markdown.py · lines 156–190 · verdict refuted
Hypothesis The cache appeared to store raw rendered HTML and run the sanitizer on read, which would let a poisoned entry serve unsanitized markup to the next reader. Why it fails Read tracing shows the sanitizer runs before the cache write, not after the read. Every cached value is already scrubbed. Poisoning the cache with raw markup is not reachable from any write path.
Critique log — “Traced every writer into the cache. All paths pass through sanitize(). Hypothesis falsified.”