Mapping the Attack Surface of a Real System
Take an architecture diagram and colour every node by exposure — public, authenticated, internal, privileged, highly sensitive — because the pattern that appears is usually more informative than any individual finding.
Frame the problem
Security starts with a concrete asset, attacker capability and trust crossing.
Five colours
Take the architecture diagram the team already has and add one attribute to every node: who can reach it. Five categories are enough and more become unusable.
Public — reachable with no credential at all. Authenticated — reachable by any account holder. Internal — reachable only from inside the network or mesh. Privileged — performs actions that grant access, move money, or change infrastructure. Highly sensitive — holds data whose exposure is materially damaging: credentials, payment data, private messages, health information.
The map is read for patterns rather than for individual nodes. A public node adjacent to a highly sensitive one is the shortest path in the system and deserves the most review. A privileged node with an authenticated inbound edge means any customer can reach code that performs privileged operations, and the only thing between them is an authorization check. An internal node with an edge from a public one — a service the frontend can call directly, an internal API behind the same load balancer — means "internal" is aspirational.
The three questions the map answers
How many hops from public to highly sensitive? Count the shortest path. Two hops is normal for a web application and means the intermediate node carries the entire authorization burden. One hop is a finding. Four hops with different identities at each is a well-segmented system, and you can say so specifically rather than vaguely.
Which single node, if compromised, reaches the most? Compute reachability from each node using the credentials it holds. The answer is rarely the one people expect: it is often a background worker or a CI runner rather than the customer-facing API, because those hold broad credentials and receive less review. That node is where hardening effort belongs.
Where does the colour change without a control? Every edge from a lower-trust colour to a higher-trust one should name the control that makes the crossing safe — authentication, signature verification, a scoped role, an approval. Edges that cannot name one are the report, and they are usually edges nobody thought of as a boundary because both ends are "ours".
| Pattern | What it means | What to do |
|---|---|---|
| Public node adjacent to highly sensitive | One authorization check is the whole defense | Add depth: scoped role, row policy, egress control |
| Privileged node with authenticated inbound | Any customer can reach privileged code | Separate network path and identity for admin surfaces |
| Internal node reachable from public | "Internal" is a naming convention, not a control | Enforce with network policy, not with documentation |
| One node reaching everything | Single point of total compromise | Split its credentials; usually a worker or CI runner |
| Edge with no named control | An unexamined boundary | Name the control or accept the risk explicitly |
Key points
- Colour every node by exposure — public, authenticated, internal, privileged, highly sensitive — and read the map for patterns, not nodes.
- Count hops from public to highly sensitive; one hop means a single check is the entire defense.
- The node that reaches the most is usually a worker or CI runner, not the customer-facing API.
- Every edge that raises trust must name its control; edges that cannot are the finding.
- "Internal" must be enforced by network policy, or it is a naming convention.
Boundary control exercise
This lesson uses the shared boundary-control exercise.
Attack Surface Mapper
- • Browser → API: authenticate the caller, validate the data and authorize the operation.
- • Backend → Database: authenticate the caller, validate the data and authorize the operation.
- Unmarked: User → Browser, API → Backend. If the other side were hostile, would anything here need checking?
- • Identity question: which component authenticates human and machine principals?
The builder suggests questions, not certainty. Verify each control in code, policy and production configuration; record residual risks and unknowns.
Follow the attack
Safe conceptual simulation: capability → missing control → crossed boundary → asset impact.
- 1Attacker → the shortest public-to-sensitive path, because effort is finite and that path has the fewest controls to defeat.
- 2Path → the widest-reaching node, to convert a foothold into general access.
- 3Wide node → everything it can reach, using its own credentials rather than exploiting anything further.
- A one-hop path means a single missing check exposes the primary data store.
- A single wide-reaching node means the incident scope is "everything" regardless of where the attacker entered.
Defend, detect, recover
One prevention is a single point of security failure. Layer it and make failure observable.
- • Increase hop count between public and sensitive by inserting components with independent identities, not just more code.
- • Split the credentials of any node that reaches everything; usually this is one config change with large effect.
- • Enforce internal-only with network policy and workload identity so the colour on the map matches reality.
- • Regenerate the map from infrastructure state on a schedule and diff it; new edges are the signal.
- • Alert on any new path from a public node to a highly sensitive one.
- • Use the map to scope: what could the compromised node reach, with which identity, and what was in reach transitively?
- • Cut the edge before fixing the code — network and IAM changes are faster than deploys.
- • The map reflects declared architecture; undeclared paths (a debugging tunnel, a shared VPC peering, a vendor agent) do not appear.
- • Colouring is a judgment and "internal" gets applied optimistically.
- • Reachability through data — a shared queue, a shared bucket — is easy to miss when only request edges are drawn.