Northwind Studio
client cabinet
- Scope
- Access · payments · the AI · data · infra
- Took
- 5 working days
- Reviewer
- Independent audit
- Findings
- 12 ranked
- 01 · CriticalThe database key is in the browser
- 02 · CriticalChange the number, read someone else's invoice
- 03 · CriticalA forged message marks an invoice paid
- 04 · HighDouble-tap Pay, charged twice
- 05 · HighThe cabinet bot reads every client's files
- 06 · HighMoney is stored as a decimal that drifts
Fix these six — the three critical and three high — and the cabinet is safe to launch. The rest are schedule, not blockers.
Summary
Automatic tools found 0 of these 12. The dependency scanner flagged 17 out-of-date-library advisories and the secret scanner found 0 stray keys — but none of these findings, which are about how money, access and files move. Every one came from reading the code by hand. 8 of 12 are the same class of bug this studio has written up before.
Findings
Critical · 3
The database key is in the browser
The master key to the whole database is sitting in the web page, where any visitor can copy it.
For Northwind: With that key, anyone reads and changes every client's invoices and files directly, not just their own. The login in front of it stops nothing.
Fix: Keep the full-rights key on the server; give the browser a key scoped to the logged-in client, or no key at all.
Reference: 4.1 Someone Else's Files
Change the number, read someone else's invoice
To see an invoice the cabinet only checks that you're logged in. Change one number in the address and you're looking at another client's invoice.
For Northwind: Logged in as Brightlane, change the number and another client's invoice opens: amount, plan, payment status. Nothing was hacked.
Fix: Check the invoice belongs to the logged-in client, and let the database refuse the rest even if a page forgets.
Reference: 4.1 Someone Else's Files
A forged message marks an invoice paid
When the payment company says an invoice is paid, the cabinet doesn't check the message is really from them. A faked message works just as well.
For Northwind: A €5,800 invoice flips to paid with no money behind it. The studio ships the work, then finds the money never arrived.
Fix: Verify the provider's signature over the raw body before acting, and ignore anything that fails.
Reference: 2.3 Webhooks
High · 3
Double-tap Pay, charged twice
If you tap Pay twice, or your phone retries, you're charged twice for the same invoice.
For Northwind: The €5,800 Studio retainer comes out of a client's account twice. They notice before the studio does.
Fix: Carry one idempotency key per payment all the way to a unique constraint in the database.
Reference: 2.2 Idempotency
The cabinet bot reads every client's files
The help bot reads every client's files to answer anyone. It just hides where the answer came from.
For Northwind: A client asks about their own project and the answer quotes Tidepool's confidential file. Tidepool signed a confidentiality clause.
Fix: Search only the files that client may open, so the bot never reads the rest.
Reference: 4.2 The Bot Knows Too Much
Money is stored as a decimal that drifts
Money is kept as the kind of number that can't hold exact cents. Split a bill in two and a cent goes missing.
For Northwind: Split invoices and partial payments stop adding up. By month end the books and the bank disagree, and nobody can say why.
Fix: Store money as whole cents in integers; split with a method that assigns the leftover cent on purpose.
Reference: 2.6 Money Math
Medium · 4
Personal data in briefs goes to the AI
Anything a client puts in a brief is sent to the AI as-is, even personal details they shouldn't have shared.
For Northwind: Halden's brief has patient records in it. They leave the building for a third-party model with the rest of the text.
Fix: Swap personal data for placeholders before sending, and put it back only for the person reading the answer.
Reference: 4.4 What Leaves for the AI
File links never expire
A link to a file works forever, for anyone who has it, long after the project ends.
For Northwind: The freelancer who rebuilt the cabinet still has links to a finished project's files. They open fine today.
Fix: Sign links, expire them in minutes, bind them to one person, and kill them when access is revoked.
Reference: 4.6 The Link That Never Dies
No limit on logins or bot questions
Nothing stops someone trying thousands of passwords, or asking the bot so many questions it runs up a bill.
For Northwind: One client account is one guessed password away from the invoices behind it, and the AI bill has no ceiling.
Fix: Count attempts per account and per address, slow them down after a few, and cap the bot's spend.
Backups run, restore was never tested
The cabinet is backed up every night, but nobody has ever checked that a backup can actually be put back.
For Northwind: The one morning the database is lost, the studio finds out whether the backups work. A backup you can't restore is a file, not a backup.
Fix: Restore a backup into a scratch database on a schedule and check row counts; a backup is only real once it's been put back.
Low · 2
Secrets printed to the logs
The cabinet writes its passwords and keys into its logs, where more people can see them than should.
For Northwind: The secrets you'd rotate after a breach are already sitting in the log history, waiting to be read.
Fix: Keep secrets out of logs; redact known key shapes before anything is written.
No staging, deploys from a laptop
There's only the live site. New versions go straight onto it from someone's laptop, with nowhere to test first.
For Northwind: Every change is tried for the first time on real clients. A bad release is live until someone's laptop fixes it.
Fix: Add a staging copy, deploy from a pipeline, and keep the last good release to roll back to.