Your microservices trust each other implicitly. Service A calls Service B with no authentication. Service B trusts the request because it arrived on the internal network. Should it?
The perimeter model assumes one boundary at the edge. Inside that boundary, every service trusts every other. This model was correct in 1998. It is wrong now. The moment one internal service is compromised, the attacker has the same trust every other service has. This is FM10 — Security Breach. It is the failure mode that reveals a security boundary you never drew.
The incident
A B2B SaaS product exposes a public API behind an authenticated gateway. Behind the gateway sit twelve microservices. The gateway validates the user token. It attaches the user ID to the request. It forwards the request to the appropriate internal service.
The internal services trust the user ID header. They perform no further validation. This design was chosen for AT5 — Centralisation vs Distribution. Centralising authentication at the gateway is simpler. Every service does not need to know how to validate tokens. Every service does not need to talk to the identity provider.
On a Wednesday, an image-processing service — one of the twelve — is compromised through an unpatched dependency vulnerability. The attacker gets shell access on one pod. From that pod, the attacker can reach every other internal service directly. The gateway is not in the path.
The attacker sends a request to the billing service. The request sets the X-User-Id header to the account ID of the largest customer. The billing service trusts the header. It returns three years of invoice data. The attacker sends another request to the reports service, this time impersonating the CFO of that customer. The reports service returns the raw revenue export.
No alert fires. Every request looks like a normal internal call.
What failed
The immediate failure was FM10 — Security Breach. But FM10 is a family of failures. The specific instance here is trust based on network location. The system assumed that reaching an internal endpoint proved authorisation. The assumption was never true. It only appeared true while no attacker was inside.
The tradeoff being made was AT5 — Centralisation vs Distribution. The team centralised authentication at the gateway. They accepted the risk of trusting internal traffic. They did not name the risk. They did not name the tradeoff. They inherited a diagram from three years earlier and did not ask what it assumed.
The reference chapter names the formation mechanism directly. FM10 forms from absent or misconfigured Security Boundaries. It forms from Least Privilege violations. It forms from unpatched vulnerabilities. It forms from credential theft in code, environment variables, or logs. This incident hit three of the four in sequence.
The compounding pattern
FM10 rarely arrives alone. The reference chapter names a specific compounding pattern: FM10 often follows FM3 or FM5. An attacker uses a system's resource consumption or latency amplification to extract information through timing attacks. Or the attacker exhausts resources as a distraction while exfiltrating data.
In this incident, the compounding was different. The attacker did not need timing tricks. The compounding was with FM11 — Observability Blindness. The internal calls carried no attribution. Every request looked like every other request. The team could not distinguish a legitimate billing lookup from an attacker's exfiltration. The absence of security telemetry inside the perimeter turned a fifteen-minute containment into a three-day investigation.
The reference chapter's rule holds. Any failure mode combined with FM11 becomes a multi-hour incident instead of a fifteen-minute recovery. FM10 combined with FM11 is worse. The attacker has time.
The signal
Look at your architecture diagram. Pick any two internal services. Ask: what authenticates the call from service A to service B? If the answer is "they are both on the internal network," you have this failure mode. The perimeter is your only boundary. The perimeter is one dependency compromise away from being irrelevant.
Now ask the harder version. If an attacker gets shell access on any one pod in your cluster, which other services can they call? Which data can they read? Which writes can they issue? If you cannot answer, you are running the pre-incident version of this system.
What the reference chapter says to do
The prevention list in the reference chapter is short and specific.
Security Boundaries at every service-to-service call. This is Zero Trust. The name is a design principle, not a product. The principle: no network location grants trust. Every call authenticates. Every call authorises. The perimeter is not a boundary — every service is a boundary.
Least Privilege for all credentials. The billing service credential can read invoice data. It should not be usable to read anything else. The reports service credential should not have write access. The image-processing service credential should not have access to billing at all. If one credential is stolen, the blast radius is bounded by what that credential can do.
Secrets management, not environment variables or source code. Credentials in .env files leak through logs. Credentials in source code leak through repository access. A secrets manager keeps credentials out of every place that gets accidentally read.
Regular dependency audits for known vulnerabilities. The image-processing service was compromised through an unpatched dependency. The vulnerability had a CVE. The CVE had a patch. Nobody ran the audit.
OWASP Top 10 as a design checklist. Not as a certification. As a checklist you run against your design before it ships.
The tradeoff, named
Zero Trust is not free. Every service-to-service call now performs authentication. This adds latency. Every service needs credentials. This adds operational complexity. Every credential needs a rotation policy. This adds process.
The tradeoff is AT5 — Centralisation vs Distribution. The perimeter model centralises trust at one boundary. Zero Trust distributes trust to every boundary. Distribution costs more to run. Distribution fails safely when one component is compromised. Centralisation costs less to run. Centralisation fails catastrophically when the boundary is bypassed.
You are choosing between "cheap to operate, catastrophic when breached" and "expensive to operate, contained when breached." Name the tradeoff before you accept it. The team in this incident did not name it. They inherited the cheap side without knowing they had chosen.
What the post-mortem produced
The team's remediation had five parts.
They put mutual TLS on every service-to-service call. The receiving service verifies the caller's certificate. Network location grants nothing.
They replaced the trusted X-User-Id header with a signed token issued at the gateway. Internal services verify the signature before trusting the user identity. Impersonation now requires the gateway's signing key, not just network access.
They scoped every service credential to the minimum data it needs. The image-processing service can read image blobs. It cannot read billing. It cannot read reports. It cannot list users.
They moved every credential from environment variables to a secrets manager with short-lived tokens. A stolen credential expires within the hour.
They added an internal-traffic audit log. Every service-to-service call is now attributable. The next attacker leaves fingerprints.
None of these are new ideas. Every one of them appears in the reference chapter as prevention for FM10. The team did not lack knowledge. They lacked a moment where someone drew the boundary on the diagram and asked what was on the other side.
The harder question
The remediation above closes the specific path the attacker used. It does not close every path. The team now has service-to-service authentication. What authenticates the human developer running a debugging query? What authenticates the batch job that runs at 3 AM? What authenticates the observability agent that reads logs from every pod?
Every one of those is a service-to-service call. Every one of them is a boundary. Every boundary that is not drawn is a boundary the next attacker will find.
The concept is one boundary. The work is finding every one of them in your system before the attacker does.
The full framework treatment — compression blocks, three-level exercises, and the complete AT/FM mapping — is in the Reference Book, Chapter 7 (Failure Modes). Free chapter available at computingseries.com/books/ref.