tallybook.example
Tallybook is a multi-user invoicing app built with Lovable, using Lovable Cloud for data and sign in and Stripe for subscriptions. Eight items applied. Two need fixing before launch, both under a day of work. Two more belong in the first week. Three were verified, and one stays not verified with the access shared.
Recommendation: hold the launch until items 1 and 2 are fixed and re-checked. Items 3 and 4 can follow in the first week.
- 01
One account reading another account's data
Needs fix, Before launch- Signed in as test account B, opening the address of an invoice that belongs to account A showed the full invoice. Signed out, the same address showed nothing.
- Any customer can read any other customer's invoices by changing an id. That is a disclosure you would have to tell every customer about.
- Add a row rule on the invoices table that only lets an account read and change rows it owns, then repeat the request as account B and confirm it returns nothing. Under an hour.
- 02
Payment handling
Needs fix, Before launch- In the repository, the subscription webhook grants the plan before checking the event signature, and nothing records which events were already handled.
- Anyone who finds the webhook address could grant themselves a paid plan, and a retried event would run the grant a second time.
- Verify the Stripe signature before reading the event, store each event id once, and ignore an id you have already processed. Two to three hours.
- 03
Rate limiting and abuse controls
Needs fix, This week- In the repository, the sign up handler sends a welcome email on every request and has no limit per address. Not tested with repeated sign ups, since that would send real email.
- A script could use up your email sending quota and fill your user table with junk accounts in an afternoon.
- Limit sign ups per address and per email domain, and add a quiet bot trap field to the form. An afternoon.
- 04
Key rotation
Needs fix, This week- The owner's settings screenshots show the Stripe secret key stored twice: once in the backend secrets and once in a scheduled job's settings. Nothing records where each key is used.
- If the key leaks, rotating it breaks the scheduled job without warning, so a rotation becomes an outage.
- Keep the key in one place, have the job read it from there, and write down every key with where it lives. Under an hour.
- 05
Database row rules
Verified- In the repository, row rules on customers, payments and settings each limit reads and writes to the owning account. As account B, the pages for account A's customers, payments and settings showed nothing.
- 06
Sign in and account flows
Verified- Sign in, password reset and sign out behaved as expected for both test accounts. Opening a dashboard address signed out went to the sign in page.
- 07
Rollback and recovery
Verified- On a shared screen, the owner restored the previous version from the builder's history in under two minutes.
- 08
Error monitoring
Not verified- No monitoring access was shared, and the owner said none is set up. Left as Not verified rather than passed.
- Connect an error monitoring service and send one deliberate error to confirm an alert reaches you within five minutes.
In the invoices table, add a row rule so a signed in account can only select, update and delete rows where owner_id equals its own user id. Do not change any other table. Then show me the rule you added and the query I can run as a second account to confirm it returns no rows.
- Behaviour under heavy real traffic.
- The internal behaviour of Stripe, the email provider and the hosting platform.
- Anything outside the published address and the access shared.
A 14 minute recording following the same order, item 1 first.
