{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreicmwcy23yibzpahln664whfdcnkc4aq3wkghr472bjrs2zgqb3sru",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3moxqjpxbx4g2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreifvvidoe4qpyqk2xgpiquldn3gdq3iap6ws3cavoso5bckxno7nxy"
},
"mimeType": "image/webp",
"size": 75842
},
"path": "/victor_areyzaga/the-tool-found-corridor-nodes-but-the-bigger-finding-was-where-it-found-none-2m33",
"publishedAt": "2026-06-23T15:36:00.000Z",
"site": "https://dev.to",
"tags": [
"security",
"docker",
"appsec",
"opensource",
"corridor-lab",
"accguard",
"corridor-id",
"github.com/rodrigo-areyzaga/corridor-id"
],
"textContent": "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.\n\nThe 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.\n\nSo 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.\n\nThen I pointed it at four architecturally different Docker environments.\n\nTwo had corridor nodes. Two had none.\n\nBoth answers were useful. But the zero-corridor results taught me more than the positive ones.\n\n## What corridor-id does\n\nThe 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.\n\nThe output is a ranked list with two metrics: exposure distance (how close to the surface) and forward reach gain (how many deeper nodes become reachable through this node).\n\nOne command:\n\n\n\n python corridor-id.py docker-compose.yml\n\n\nNo manual path declaration. No value labels. No configuration. From graph position alone.\n\n## The four tests\n\n### corridor-lab — segmented, depth 3\n\nMy 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.\n\n\n\n Corridor nodes found: 3\n\n → status-api\n Exposure distance: 1\n Forward reach gain: 1\n\n → log-monitor\n Exposure distance: 1\n Forward reach gain: 1\n\n → internal-admin-api\n Exposure distance: 2\n Forward reach gain: 1\n\n\nThis was validation that the tool's graph logic matched the lab's manual analysis.\n\n### Sock Shop — segmented test variant, depth 3\n\nWeaveworks' 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.\n\n\n\n Corridor nodes found: 6\n\n → front-end\n Exposure distance: 1\n Forward reach gain: 6\n\n → orders\n Exposure distance: 2\n Forward reach gain: 3\n\n → shipping\n Exposure distance: 2\n Forward reach gain: 2\n\n\n`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.\n\n### OWASP crAPI — flat, no segmentation\n\nTen services. One default network. Every service can reach every other service.\n\n\n\n Corridor nodes found: 0\n\n\n### Docker Example Voting App — segmented-looking but flat in practice\n\nFive services. Two networks. But both exposed services sit on both networks.\n\n\n\n Corridor nodes found: 0\n\n\n## What the zero-corridor results actually mean\n\nMy first instinct when crAPI returned zero corridor nodes was that the tool had nothing to say about it. No finding. Nothing to report.\n\nThat instinct was wrong.\n\ncrAPI 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.\n\nThe 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.\n\nThe 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.\n\nIn a segmented topology, corridor-id finds corridor nodes.\n\nIn 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.\n\n## The distinction that matters\n\nCorridor topology: some nodes control movement between zones. Those are corridor nodes and they deserve monitoring proportional to their reach.\n\nFlat 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.\n\nThe tool can distinguish between these two conditions. That distinction is, I think, the more interesting finding.\n\n## What corridor-id does not claim\n\nThe 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.\n\nThe 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.\n\nThis is a v0.2 tool with a narrow promise: given a topology, identify which nodes are corridor nodes. It does that one thing.\n\n## The through-line\n\naccguard tests whether authorization boundaries hold under replay.\n\ncorridor-lab proves that a service's risk depends on where it sits in the path, not what it stores.\n\ncorridor-id identifies corridor nodes from topology — automatically, from graph position alone.\n\nEach one asks the same question at a different layer: **does the security posture match what the architecture actually allows?**\n\n## The repo\n\ngithub.com/rodrigo-areyzaga/corridor-id\n\n\n\n git clone https://github.com/rodrigo-areyzaga/corridor-id\n cd corridor-id\n pip install pyyaml\n python corridor-id.py your-docker-compose.yml\n\n\nThe 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.\n\n## A note on how this was built\n\ncorridor-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.\n\nI'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.",
"title": "The Tool Found Corridor Nodes — But the Bigger Finding Was Where It Found None"
}