Security
When something is exposed
What to do, in order, when data or a credential has been reachable by someone who should not have reached it.
When something is exposed
Order matters. Stop the bleeding, then measure, then tell people, then prevent the recurrence. Doing these out of order is how a small exposure becomes a disclosure problem.
1. Close it — minutes, not hours
Guard the route or revoke the access. Ship it on its own, ahead of any investigation. A partial fix deployed now beats a complete fix deployed after lunch.
Verify from outside the app — an unauthenticated request from a machine with no session. Reading the code and concluding it is fixed is not verification.
2. Rotate anything that was reachable
If a credential was exposed, it is burned. Rotate it even when the logs suggest nobody fetched it — absence of evidence in logs that were not designed as an audit trail is not evidence of absence.
Rotating PORTAL_SESSION_SECRET invalidates every owner and portal session instantly, without changing anybody's password. That is the lever for "a laptop is missing".
3. Establish the blast radius
Three questions, answered honestly:
- What was reachable? Not "what did the route intend to return" — fetch it and read the response.
- For how long? Find the commit that introduced it.
- Was it indexed or cached? A public JSON endpoint can be in a crawler's cache after the fix.
4. Decide on disclosure
If personal data belonging to a client's customers was exposed, the client is told. That is their decision to make about their own people, not ours to sit on. Say what was reachable, for how long, and what has changed.
Do not send a legally hedged non-statement. The relationship survives an honest disclosure far more often than it survives finding out later.
5. Make the class of bug impossible
The last step, and the one that gets skipped. Not "fix this route" — remove the way it happened.
The same brand-config leak existed on three routes on 2026-09-02. Fixing them one at a time is what let the third survive the first fix. The durable fix was one shared guard plus an audit that fails the build, so the fourth route can never be written.
Ask: what would have caught this automatically? Then build that.