Assume breach by default.
Design as though the attacker is already the one calling your endpoint. The most dangerous vulnerabilities are not exotic exploits — they are conveniences that behave exactly as built, for the wrong caller.
1. The mindset, not a control
“Assume breach” is the posture that makes every other tenet coherent. It instructs the designer to evaluate each interface from the adversary’s seat: not “how will a legitimate client use this?” but “what does this give an attacker who already has a foothold, a stolen token, or simply patience?” Perimeter thinking asks whether someone can get in. Assume-breach thinking accepts that someone already has, and asks what they can reach next.
2. The convenience that becomes an oracle
Consider the canonical example: a public endpoint that confirms whether an account exists — a password-reset form that says “no account with that email” versus “check your inbox.” To a product manager it is helpful UX. To an attacker it is a customer-enumeration oracle that converts a breached email list into a confirmed list of your users, ready for targeted phishing and credential stuffing.
The fix is to design the response so it leaks nothing the caller has not earned. Reset flows should return an identical message regardless of whether the account exists; lookups should be uniform in shape and timing.
// Leaks existence — an enumeration oracle
if (user is null) return NotFound("No account with that email");
await SendReset(user); return Ok("Reset link sent");
// Uniform — reveals nothing to an unauthenticated caller
if (user is not null) await SendReset(user);
return Ok("If that account exists, a reset link has been sent");3. What it changes in design
Assume-breach is a design-time discipline, applied before code exists:
- enumerate the abuse cases beside the use cases — for every feature, name how it serves an attacker;
- treat error messages, timing, and response shape as information disclosure, and make them uniform for unauthorized callers;
- default new endpoints to deny, and grant access deliberately rather than removing it after the fact;
- assume any internal service can be reached from outside, because eventually one will be.
4. How B5 Secure enforces it
B5 Secure encodes assume-breach as the system’s default state. Endpoints are closed until a request passes the full verification pipeline, so a forgotten authorization check fails safe instead of failing open. There are no internal-only exemptions for the pipeline to skip, and the framework favors responses that disclose nothing to a caller who has not proven entitlement. The result is that the “convenient” mistake — the endpoint someone left open “just for testing” — is structurally hard to make.