00 — EXECUTIVE SUMMARY
Seven findings.
Two need immediate attention.
This fictional app exposes a database table and a privileged key. Those two issues put customer data and administrative access at risk. Address them first, then work through the remaining access and configuration issues.
02CRITICAL
02HIGH
02MEDIUM
01LOW
ALL EVIDENCE BELOW IS FICTIONAL AND REDACTED. NO REAL CUSTOMER DATA IS SHOWN.
FINDING 01 / 07CRITICAL
Database table accessible without row-level security
A public request returned rows from a customer table without signing in. Customer records are exposed to anyone who knows where to look.
Evidence
GET /rest/v1/meal_plans?select=id HTTP/1.1
HTTP/1.1 200 OK
content-range: 0-0/1204
Response body: [REDACTED]
Fix prompt
Enable row-level security on the meal_plans table. Add policies so authenticated users can only read, insert, update, or delete rows where user_id matches their authenticated user ID. Deny anonymous access. Test with two separate accounts and confirm each cannot access the other’s rows.
FINDING 02 / 07CRITICAL
Service-role key exposed in the JavaScript bundle
A privileged key was included in code sent to browsers. Anyone with the key can bypass database access rules.
Evidence
GET /assets/app.[REDACTED].js HTTP/1.1
HTTP/1.1 200 OK
Matches: 1 privileged key
service_role_key = "[REDACTED]"
Fix prompt
Remove the service-role key from all client-side code and build-time public environment variables. Rotate the exposed key immediately. Move privileged operations to a server-side function with authorization checks, and use only the public client key in the browser. Rebuild and check the bundle for the old key.
FINDING 03 / 07HIGH
No rate limiting on login
Repeated login attempts were accepted without a meaningful limit. This makes automated password guessing easier.
Evidence
POST /auth/login HTTP/1.1
HTTP/1.1 401 Unauthorized
Failed attempts: 50 / 50 accepted
Rate-limit responses: 0
Fix prompt
Add server-side rate limits to login attempts by account and IP, with a temporary cooldown and a generic error response. Configure limits at the authentication provider or server, not only in the browser. Test repeated failures and ensure legitimate users can recover access.
FINDING 04 / 07HIGH
Signup response reveals existing users
Different signup messages reveal whether an email address is already registered. An attacker can use this to compile a list of users.
Evidence
POST /auth/signup HTTP/1.1
Existing address: HTTP/1.1 409 Conflict
New address: HTTP/1.1 200 OK
Addresses tested: 2 [REDACTED]
Fix prompt
Make signup responses indistinguishable for existing and new email addresses, including status codes and user-facing messages. Send the appropriate next step by email without revealing account existence in the response. Add rate limiting and test both cases.
FINDING 05 / 07MEDIUM
Security headers are missing
The app does not instruct browsers to apply several useful protections. This leaves browser-based attacks more room to work.
Evidence
GET / HTTP/1.1
HTTP/1.1 200 OK
Content-Security-Policy: [MISSING]
X-Content-Type-Options: [MISSING]
Fix prompt
Configure the hosting layer to send X-Content-Type-Options: nosniff and a restrictive Content-Security-Policy suited to the app’s actual scripts, styles, and connections. Test the policy in report-only mode first, resolve violations, then enforce it.
FINDING 06 / 07MEDIUM
Outdated dependency with a known vulnerability
The installed version of lodash is affected by a known command-injection issue. Exploitability depends on how the app uses the affected functions.
Evidence
GET /package-lock.json (local audit copy)
Dependency matches: 1
package-lock.json: lodash 4.17.20
Advisory: CVE-2021-23337
Fixed version: 4.17.21
Fix prompt
Upgrade lodash to at least 4.17.21, update the lockfile, and run the application’s tests. Check whether lodash is direct or transitive and update the parent dependency if necessary. Re-run the dependency audit and review remaining advisories.
FINDING 07 / 07LOW
Session data stored in localStorage
JavaScript running on the page can read session data from localStorage. A successful script injection can expose the session.
Evidence
Browser storage: localStorage
Session entries: 1
Key: [REDACTED SESSION KEY]
Value: [REDACTED]
Fix prompt
Review the authentication provider’s supported session storage options. Where supported, move session tokens to Secure, HttpOnly, SameSite cookies with appropriate CSRF protection. Remove old localStorage tokens and test sign-in, sign-out, refresh, and cross-site request handling.