BrightPocket Software Demonstration Case Study
Evidence: Verified Technical Proof
A green build was hiding a cross-tenant data leak
A near-launch multi-tenant SaaS application was deliberately built with the kinds of defects that appear in AI-assisted and inherited codebases, frozen in that state, then diagnosed and repaired using the standard recovery method — and finally verified in a real hosted environment, not just locally.
Demonstration, not client work. ClientFlow is a demonstration application built by BrightPocket Software to show how it recovers existing software. It is not client work. No customer paid for it, and no customer data appears in it.
Evidence status — Verified Technical Proof. Real software, really built, diagnosed and repaired — then verified against the deployed application rather than only on a laptop. 15 / 15 hosted browser tests and a 24 / 24 hosted acceptance matrix are recorded.
Starting condition
Everything that normally signals “ready” was green
ClientFlow is a small multi-tenant client and project tracker: register, log in, add clients, attach projects, move them through a status. Each organization gets its own workspace.
What the usual checks reported
- `npm run build` succeeded
- TypeScript reported no errors
- Every screen rendered and every button worked
- Row Level Security was enabled on all four tables
None of those signals touched the four things that actually mattered.
The business risk
A single signed-in customer could read every other customer’s client list and project pipeline.
For a product whose entire promise is “your workspace, your data,” that is not a defect to schedule for next sprint. Shipping it would have disclosed customer records to other customers on day one — with no logging to establish who saw what.
Diagnosis
Six findings, ranked by real risk
The broken state was frozen as a tagged commit before anything changed. Each fault was reproduced and evidenced before it was diagnosed, and diagnosed before it was repaired.
Cross-tenant data leak
Critical- What was found
- Row Level Security was enabled on every table — which is why a casual review passed — but every policy was written as `USING (true)`, which admits every row to every authenticated user.
- Why it mattered
- Signed in as a second organization, I could read the first organization's entire client and project list. For a product whose promise is "your workspace, your data", shipping this would have disclosed customer records to other customers on day one, with no logging to establish who saw what.
- Repair
- Policies rewritten to scope both reads and writes to the caller's organization, resolved server-side through a `SECURITY DEFINER` helper rather than trusting anything the client sends.
Session invisible to the server
Critical- What was found
- The application stored its login session in browser storage that is never transmitted with a request. After a successful login the browser held a valid session and the server held nothing.
- Why it mattered
- Because the server could not identify the user, every protective check had been pushed into the browser, where it cannot be trusted.
- Repair
- Session moved onto cookies the server can verify, with a server-side check at the data access layer.
Protected routes were not protected
High- What was found
- The only route guard redirected after the protected page had already been delivered and painted. An anonymous request to the dashboard returned HTTP 200 with the full logged-in shell.
- Why it mattered
- The protected area was being served to anonymous visitors as static HTML. The build output had been saying so all along — the protected routes were marked static.
- Repair
- Server-enforced protection, verified by tests that make anonymous requests and assert on the response rather than on what the browser eventually displays.
Silent configuration fallback
High- What was found
- A missing configuration value fell back to a plausible default instead of failing.
- Why it mattered
- A misconfigured deployment could ship successfully while pointing every visitor's browser at the wrong backend.
- Repair
- Missing configuration now fails the build loudly and names the variable that is absent.
Duplicate submissions
Medium- What was found
- A double-click created two records.
- Why it mattered
- Duplicate data with no constraint preventing it.
- Repair
- Submission handling corrected and a database constraint added, so correctness does not depend on the interface behaving.
No regression coverage
Medium- What was found
- Zero automated tests. Nothing prevented any of the above from returning.
- Why it mattered
- Every fix would have been one refactor away from silently reverting.
- Repair
- 15 browser tests covering each repaired guarantee, including one that signs in as a second organization and proves it sees nothing.
The decision
It did not need a rewrite
The database design, signup logic, routing, and interface were sound. The problems were concentrated in a handful of decisions about session storage, access enforcement, and configuration.
A rewrite was considered and rejected on the evidence. Preserving working code was cheaper, faster, and lower risk — and it is the recommendation we would have made to a paying client in the same position.
Preserved untouched
- Database schema and table design
- Signup and account provisioning logic
- Routing and page structure
- The entire user interface
A defect that only existed once it was deployed
Finding HD-01 — hosted environment only
Hosted Supabase projects ship default privileges that grant broad table access to the anonymous role. Those defaults applied automatically as the migrations created each table, silently widening the deliberate least-privilege grants — on the hosted project only.
The local development stack does not seed the same defaults. So local matched the intended design, hosted did not, and nothing failed to reveal it. The full test suite passed against a hosted database that was not the one we designed.
Impact. No data was exposed. Row Level Security still held, and that was verified against real rows — including an unfiltered anonymous bulk delete, which removed nothing. What was lost was defense in depth: the second layer beneath RLS was silently absent.
Repair. A migration re-asserts the intended privileges. It only ever removes permissions, so it cannot weaken authorization. The anonymous role now holds no table privileges and is refused at the grant layer before RLS is even consulted.
The lesson. Verify the target environment. A passing local test suite says nothing about privileges the hosting platform grants behind your back — and this is exactly the class of defect that reaches production because every check was green.
Verification
Proven where it counts — in the deployed environment
Local results are not hosted proof, and we do not present them as such. Everything below ran against the live application.
Local verification
- Playwright browser tests
- 15 / 15 passed
- Production build
- Pass
- TypeScript
- Pass
- Lint
- Pass
Hosted verification
- Playwright, against the deployed application
- 15 / 15 passed
- Hosted acceptance matrix
- 24 / 24 passed
- Cross-tenant read, by list and by direct record id
- Blocked
- Cross-tenant insert, update and delete
- Rejected
- Anonymous read, write and bulk delete
- Denied
- Duplicate submission
- Prevented
- Session revocation on sign-out
- Verified
Honest limitations
What this demonstration does not prove
A case study that lists only strengths is marketing. These are the boundaries of what the work above establishes.
- ClientFlow is deliberately small. It demonstrates a recovery method on a realistic set of defects; it is not a production SaaS product.
- The defects were introduced intentionally so the baseline could be frozen and evidenced. They are representative of real AI-assisted codebases, but they were not discovered in a customer system.
- No formal penetration test or security certification was performed, and none is claimed.
- Accessibility and performance were not in scope for the demonstration.
- The live demo runs on free-tier hosting, which can pause after inactivity. If it does not respond, that is the hosting tier, not the application.
Before you rely on the live demo
It runs on free-tier hosting, which can pause after a period of inactivity. If you are about to show it to someone who matters, open it first — a demo that takes a moment to wake is fine, a demo that is asleep during a meeting is not.
Does any of this sound like your application?
A build that passes, screens that render, and a quiet suspicion that something underneath is not right. That is exactly what a Rescue Triage is for.
