Ship-ready. The sweep found 2 high-severity issues — both in the authentication and access-control layer, both fixed and re-verified before launch. Two medium-severity stability issues were fixed or mitigated. The product's multi-tenant isolation, bot protection, and load behaviour were verified directly against production. One low-risk item is consciously accepted and documented.
A sweep is session-based exploratory testing performed by a senior human tester, accelerated by AI tooling — not a scripted test plan, and not an automated scan.
The human decides where to dig, judges severity, and signs every finding. AI is used to move faster: generating probe scripts, simulating concurrent load, drafting reproduction steps, and sweeping wide surfaces the human then verifies by hand. Every finding in this report was reproduced before it was written down.
| Area | What was exercised |
|---|---|
| Authentication | Sign-up trigger behaviour, anonymous demo sessions, sign-out flows, session revocation timing, captcha enforcement |
| Access control | Row-level security (RLS) policy audit across all multi-tenant tables; direct API probing with real user and anonymous JWTs |
| Load & capacity | Concurrent-visitor burst against production, per-visit payload cost, auth rate-limit configuration |
| Client stability | WebGL renderer lifecycle across SPA navigation, race conditions in async UI flows, browser matrix |
Environments: production (read-only probing) and an isolated staging environment for anything invasive. No customer data was accessed or created.
The product offers a no-signup public demo that uses anonymous authentication. The database trigger that provisions a new workspace on user signup also fired for these anonymous demo sessions — so every single demo visitor caused a permanent ghost company, workspace, and profile to be created in the production database.
Beyond uncontrolled data growth, ghost tenants polluted the billing entity table and would have skewed every customer count the business relies on. Launch-day traffic would have created thousands of them in hours.
Guard added to the signup trigger: anonymous sessions return immediately and provision nothing. Re-verified by repeating the reproduction — no rows created.
A full audit of the database's row-level security policies — the layer that keeps one customer's data invisible to another — found five policies that granted broader access than intended, including definer-privilege functions that skipped membership checks. The gaps were found by reading every policy line by line and then probing the API directly with real JWTs from differently-privileged test users, not by trusting the policy names.
Withheld by design. We document access-control findings generically in public reports and provide full reproduction detail to the product owner only. (Here we are the product owner — the point stands for customer reports.)
All five policies rewritten and hardened in two dedicated migrations; membership-check helper functions made consistent. Re-probed with the same JWT matrix after deployment — all cross-tenant requests now return empty.
The demo page revokes its anonymous session when the visitor leaves. But the app's own navigation into the canvas also counts as "leaving" — so the server-side session revoke raced the canvas boot. When the revoke won, the canvas booted on a dead token and hung on an endless spinner. Timing-dependent: invisible in local development, frequent in production.
The leave-handler now recognises the app's own navigation and skips revocation for it; real departures still revoke.
Navigating demo → canvas → browser-back → demo again produced an empty canvas and an unrecoverable renderer exception (TypeError in the render-target system). Deterministic in both Firefox and Chrome. Root cause: module-level renderer state survives SPA navigation, so a second mount reuses destroyed GPU resources.
Shipped mitigation: re-entry after a previous mount forces a clean page load, wiping the stale renderer state; first-time visitors keep the fast path. Full root-cause cleanup (renderer singletons, texture caches, probe contexts) is tracked as follow-up work. We report mitigations as mitigations — not as fixes.
Switching between the two main views occasionally flashed a UI row from the outgoing view over the incoming one for ~150 ms. Cause: a CSS transition shorthand also animated the visibility property that the view switch relies on, keeping the hidden view painted after the switch. Fixed by transitioning only the intended properties. A one-line cause that took real reproduction discipline to pin down — glitch reports of this kind are verified with frame-by-frame screen capture, not dismissed.
The first-run onboarding modal raced initial data loading and could appear for users who already had content, or fail to appear for genuinely new users, depending on fetch timing. Fixed by gating the modal on data-ready state rather than mount timing.
Each public demo visit leaves one row in the authentication user table. No security or cost impact at current scale; purely hygiene. Documented with a recommendation for periodic cleanup. We list accepted risks openly rather than padding reports with them as findings — or worse, hiding them.
Passes are findings too — these were probed directly against production, not assumed:
| Check | Result | |
|---|---|---|
| Bot protection | Scripted anonymous sign-in without a captcha token rejected by the auth API (400) | Pass |
| Demo isolation | Anonymous JWTs are read-only and scoped to the demo tenant; write attempts rejected at the policy layer | Pass |
| Launch-day load | 50 concurrent simulated demo visitors: 500/500 API queries succeeded, worst-case visit ≈ 2 s under a sequential worst-case model (the real client fetches in parallel) | Pass |
| Capacity headroom | Full demo visit costs 46.8 KB of egress — ~5,000 visits ≈ 5% of the hosting plan's monthly budget; auth rate limit confirmed at a sane default | Pass |
A sweep is honest about its edges. Given another session on this product, the next charters would be:
Exactly like this one — for your product instead of ours. Fixed price, 48-hour turnaround. You get every finding with reproduction steps, severity judged by a human who has done this for a living for years, a verified-passes section, and a next-charters list. Access-control reproduction details stay private to you.