The Tool Found Corridor Nodes - But the Bigger Finding Was Where It Found None
A few weeks ago I published corridor-lab - a Docker lab that proved a triage mismatch: a service that stores nothing sensitive can become high-priority because of where it sits in the path to a sensitive downstream system. The lab proved the premise.
The next question was whether a tool could identify those nodes automatically - without manual path declaration, without value labels, from graph position alone. So I built corridor-id. You point it at a Docker Compose file. It discovers the topology, computes depth from exposed surfaces, and identifies which nodes expand forward reach into deeper parts of the environment. No asset-value labels. No sensitivity ratings. No human classification. Reach and graph position only.
Then I pointed it at four architecturally different Docker environments. Two had corridor nodes. Two had none. Both answers were useful. But the zero-corridor results taught me more than the positive ones.
What corridor-id does
The tool reads a Docker Compose file and builds a reachability graph from service definitions, network memberships, and port mappings. It then orients that graph from exposed surfaces using BFS and identifies nodes that provide forward reach - access to strictly deeper nodes that the exposed surface cannot reach directly.
The output is a ranked list with two metrics:
- exposure distance - how close to the surface
- forward reach gain - how many deeper nodes become reachable through this node
One command:
python corridor-id.py docker-compose.yml
No manual path declaration. No value labels. No configuration. From graph position alone.
The four tests
corridor-lab - segmented, depth 3
My own lab, five services across five segmented networks. The tool independently identified status-api as a corridor node - the same finding the lab was built to prove.
Corridor nodes found: 3
status-api- Exposure distance: 1 - Forward reach gain: 1log-monitor- Exposure distance: 1 - Forward reach gain: 1internal-admin-api- Exposure distance: 2 - Forward reach gain: 1
This was validation that the tool's graph logic matched the lab's manual analysis.
Sock Shop - segmented test variant, depth 3
Weaveworks' microservices demo with production-reasonable network segmentation applied for analysis. The segmentation is not how the original Compose file ships. The point was not to claim Sock Shop is segmented by default - the point was to test whether corridor-id could identify corridor nodes when meaningful network depth exists. Fifteen services, seven networks.
Corridor nodes found: 6
front-end- Exposure distance: 1 - Forward reach gain: 6orders- Exposure distance: 2 - Forward reach gain: 3shipping- Exposure distance: 2 - Forward reach gain: 2
front-end ranked first because it bridges the edge tier into six application services. orders ranked second because it bridges the app tier into both a data tier and a queue tier - disproportionate reach for a single service. The tool surfaced these findings without knowing what any service does.
OWASP crAPI - flat, no segmentation
Ten services. One default network. Every service can reach every other service.
Corridor nodes found: 0
Docker Example Voting App - segmented-looking but flat in practice
Five services. Two networks. But both exposed services sit on both networks.
Corridor nodes found: 0
What the zero-corridor results actually mean
My first instinct when crAPI returned zero corridor nodes was that the tool had nothing to say about it. No finding. Nothing to report. That instinct was wrong.
crAPI returned zero corridor nodes because it has no network segmentation. All ten services share one default network. There are no corridors because there are no walls. Every service is already reachable from every other service.
The voting app was subtler. It has two named networks - front-tier and back-tier - which looks like segmentation. But both exposed services (vote and result) sit on both networks. So the back-tier services are all directly reachable from the exposed surface at depth 1. The segmentation exists in the Compose file but doesn't create depth.
The tool correctly identified both cases. It didn't just fail to find corridor nodes - it surfaced that the architecture lacks the conditions for corridor nodes to exist. In a segmented topology, corridor-id finds corridor nodes. In a flat topology, corridor-id finds something different: there are no corridors because there are no meaningful zones. That is not a clean bill of health.
A zero-corridor result has two meanings:
- In a well-segmented topology, it may mean no node expands reach - genuinely low corridor exposure.
- In a flat topology, it means the corridor model collapsed because everything is already in the same reachability zone.
The distinction that matters
Corridor topology: some nodes control movement between zones. Those are corridor nodes and they deserve monitoring proportional to their reach.
Flat topology: there are no meaningful zones, so there are no corridor nodes. But the absence of corridors means every service sits in the same reachability zone. The path problem doesn't go away - it becomes universal.
The tool can distinguish between these two conditions. That distinction is, I think, the more interesting finding.
What corridor-id does not claim
The four environments I tested are demo and security training applications - not production systems. The flat-network pattern was common in these samples, but I'm not claiming that "most containerized applications in the wild" lack segmentation. I'm saying that in the containerized architectures I tested, flat networking was common enough that the absence of corridor nodes became its own finding.
The tool also has known limitations: it computes a global depth map across all exposed nodes (which can suppress per-entry corridor findings), it treats localhost-bound ports as exposed, and it doesn't filter Compose profiles. All documented in the repo. This is a v0.2 tool with a narrow promise: given a topology, identify which nodes are corridor nodes. It does that one thing.
The through-line
accguardtests whether authorization boundaries hold under replay.corridor-labproves that a service's risk depends on where it sits in the path, not what it stores.corridor-ididentifies corridor nodes from topology - automatically, from graph position alone.
Each one asks the same question at a different layer: does the security posture match what the architecture actually allows?
The repo
github.com/rodrigo-areyzaga/corridor-id
git clone https://github.com/rodrigo-areyzaga/corridor-id
cd corridor-id
pip install pyyaml
python corridor-id.py your-docker-compose.yml
The core topology model is format-agnostic and has been validated against hand-built topologies with no parser involved. Docker Compose is the first input adapter. The identifier logic doesn't know or care where the topology came from.
A note on how this was built
corridor-id was developed with AI assistance. Claude and ChatGPT were used as pair-programming and review tools - for implementation, stress-testing edge cases, and catching two parser bugs before release. The concept, security framing, testing direction, and all accept/reject decisions were human-directed.
I'm still exploring this. The harder question - how to move from topology analysis to detection triggers on corridor nodes - is the next problem. If you've thought about it, or if you think the framework is wrong, I'd like to hear it.
Comments
No comments yet. Start the discussion.