bookings.example.com
Summary
Two things need fixing this week: a live Stripe secret key in the JavaScript every visitor downloads, and public source maps that hand out the app's original code. The rest fits into a normal sprint. One automated finding was removed in review: the Google Maps key in the bundle is restricted to this domain, as it should be.
Findings
- Critical Live Stripe secret key in the shipped JavaScript
- Business impact · Security exposure
- Anyone who opens the booking page can use this key to issue refunds, create charges or read your customers' payment records.
- Recommended fix
- Roll the key in the Stripe dashboard today, then move the deposit and refund calls into server-side code so the key never reaches the browser.
- Effort
- Hours
- Evidence
-
/assets/index-3e7a19c0.js: sk_live_…FAKE (107 chars)
- High JavaScript sourcemaps are public
- Business impact · Security exposure
- The app's original source, including the staff screens and the deposit logic, can be downloaded and read by anyone, which makes the app cheaper to copy and to attack.
- Recommended fix
- Turn off production sourcemaps in the build (Vite: build.sourcemap false), or upload them to the error tracker only, then redeploy.
- Effort
- Hours
- Evidence
-
/assets/index-3e7a19c0.js.map: served: 200, application/json, 3,412,880 bytes; source map shape
- Medium Customer email addresses in confirmation page URLs
- Business impact · Security exposure
- The booking confirmation puts the customer's email address in the page address, where analytics tools and any site the page links to can record it.
- Recommended fix
- Use the booking ID alone in the confirmation URL and look the email up on the server, then send Referrer-Policy: strict-origin-when-cross-origin.
- Effort
- Hours
- Evidence
-
/assets/index-3e7a19c0.js: the confirmation route builds /booking/confirmed?email=…
- Medium Error pages show a stack trace
- Business impact · Security exposure
- A mistyped address shows file paths, library versions and internal structure, which shortens the work of anyone probing the app.
- Recommended fix
- Turn off debug error pages in production and log the details server-side instead.
- Effort
- Hours
- Evidence
-
/.git/HEAD: not served, but the 500 error page carries a stack trace with file paths
- Medium No Strict-Transport-Security header
- Business impact · Fundraising and enterprise sales
- Enterprise security questionnaires ask for HSTS, so its absence is an easy point to lose in a vendor review, and a first visit over plain http can be intercepted.
- Recommended fix
- Add Strict-Transport-Security: max-age=31536000; includeSubDomains in the hosting platform's headers configuration.
- Effort
- Hours
- Evidence
-
https://bookings.example.com/: header absent on the root response
- Low 1.9 MB of JavaScript before the first screen
- Business impact · Revenue
- On a mid-range phone the booking page takes several seconds to appear, which costs bookings from paid traffic.
- Recommended fix
- Split the staff screens and the calendar library into lazily loaded routes so the booking page ships only what it draws.
- Effort
- Days
- Evidence
-
/: 5 scripts, 1,992,431 bytes decoded
- Low X-Powered-By header names the framework
- Business impact · Fundraising and enterprise sales
- The header tells anyone which framework runs the app, which shortens the search for a known weakness.
- Recommended fix
- Remove the X-Powered-By header (in Express: app.disable('x-powered-by')).
- Effort
- Hours
- Evidence
-
https://bookings.example.com/: X-Powered-By: Express
Not assessed
- Data access: Data-access probes are not enabled
Versions
- Version 2: Reviewed by Aaron, 6 October 2026 (shown)
- Version 1: Automated results, 5 October 2026 · superseded
A professional review of the stated scope at the stated time. Not a security guarantee, penetration test or certification.