01 Sample report
not a client report
This is what €299 buys.
Below is a sample of the audit report format, populated with the issues we most commonly find in Lovable, Bolt and v0 apps, so you can judge the depth before you pay. It is a sample of the format, not a real client's report. Client reports are confidential.
Audit report: sample
- Fee
- €299
- Turnaround
- 48 hours typical
- Findings shown
- 5 of a typical 8–15
- Format
- severity-ranked, written
02 The findings
Five findings, ranked by severity.
Each one names the problem, why it matters, the concrete fix, and the effort to fix it. Real reports typically run 8–15.
Critical · Auth
The Supabase tables holding user profiles and orders have RLS off. Any visitor with the public anon key, which ships in your frontend bundle by design, can read and modify every row via the auto-generated REST API.
- Fix Enable RLS on all tables; add per-user policies (auth.uid() = user_id); verify with an anonymous-role test suite.
- Effort 4–6 h
Critical · Secrets
The Supabase service-role key (bypasses RLS entirely) appears in commit history from an early .env commit. Deleting the file later does not remove it from history.
- Fix Rotate the key immediately; purge history (git filter-repo) or rotate + accept history; move secrets to platform env vars; add secret scanning to CI.
- Effort 2–3 h
High · Payments
The app shows "Payment successful" based on the client-side redirect alone. There is no webhook verifying the Stripe event, so a user can reach the paid state without a completed charge, and real failed payments look identical to successes.
- Fix Implement the checkout.session.completed webhook with signature verification; gate paid features on the verified server-side state.
- Effort 4–8 h
High · Error handling
Unhandled exceptions in API routes return full stack traces (file paths, query fragments) to the browser: useful reconnaissance for an attacker, confusing for users.
- Fix Add a global error boundary on API routes: log the full error server-side, return a generic message with a correlation ID.
- Effort 2–4 h
Medium · Monitoring
There is no way to know the app is broken until a customer emails. No Sentry/uptime check, no alerting, and "production" shares a database with preview deployments.
- Fix Add Sentry (or similar) + a free uptime monitor; separate the production database from previews; alert to email.
- Effort 2–3 h
01 Critical · Auth
The Supabase tables holding user profiles and orders have RLS off. Any visitor with the public anon key, which ships in your frontend bundle by design, can read and modify every row via the auto-generated REST API.
- Fix Enable RLS on all tables; add per-user policies (auth.uid() = user_id); verify with an anonymous-role test suite.
- Effort 4–6 h
02 Critical · Secrets
The Supabase service-role key (bypasses RLS entirely) appears in commit history from an early .env commit. Deleting the file later does not remove it from history.
- Fix Rotate the key immediately; purge history (git filter-repo) or rotate + accept history; move secrets to platform env vars; add secret scanning to CI.
- Effort 2–3 h
03 High · Payments
The app shows "Payment successful" based on the client-side redirect alone. There is no webhook verifying the Stripe event, so a user can reach the paid state without a completed charge, and real failed payments look identical to successes.
- Fix Implement the checkout.session.completed webhook with signature verification; gate paid features on the verified server-side state.
- Effort 4–8 h
04 High · Error handling
Unhandled exceptions in API routes return full stack traces (file paths, query fragments) to the browser: useful reconnaissance for an attacker, confusing for users.
- Fix Add a global error boundary on API routes: log the full error server-side, return a generic message with a correlation ID.
- Effort 2–4 h
05 Medium · Monitoring
There is no way to know the app is broken until a customer emails. No Sentry/uptime check, no alerting, and "production" shares a database with preview deployments.
- Fix Add Sentry (or similar) + a free uptime monitor; separate the production database from previews; alert to email.
- Effort 2–3 h
03 The structure
What every report contains.
From Etherlabz, the audit desk
Re What every audit report contains
Plain language first, then severity
Every report opens with an executive summary in plain language, then severity-ranked findings: what broke, why it matters, how to fix it, and the effort involved.
It ends with a number
Every report closes with a fixed-price quote to fix the criticals. Most apps fit the €990 critical fix sprint, and the €299 audit fee is credited.
A "fine as-is" list
A list of what we checked and did not flag, so you know what you are not paying to fix.
Five findings shown here. Real reports typically run 8–15.
04 Next step
Get the real one.
Entry: closing
The same format, filled in with what's actually broken in your app.
Balance due one conversation
Now booking