Skip to content

Count the direct-path interop harness in security-local.md's loopback inventory - #635

Draft
dormouse-bot wants to merge 2 commits into
mainfrom
fix/loopback-inventory-fourth
Draft

Count the direct-path interop harness in security-local.md's loopback inventory#635
dormouse-bot wants to merge 2 commits into
mainfrom
fix/loopback-inventory-fourth

Conversation

@dormouse-bot

@dormouse-bot dormouse-bot commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator

docs/specs/security-local.md -> "Loopback Listeners" says "Today the set is three" and names the iframe proxy, the VS Code agent-browser stream relay, and the browser-dev bridge. pnpm lint:loopback prints 4 loopback listeners. The fourth is scripts/direct-interop/run.mjs:214server.listen(0, '127.0.0.1', …) — which the inventory has never counted. This PR corrects the count and the derivation instruction that let it drift.

No privilege gap. The harness is guarded on its own merits: it imports isOwnOrigin from lib/src/host/loopback-guard.ts and isAuthorized from standalone/scripts/dev-host-guard.mjs, and calls both before routing, so it passes the lint by reference rather than by allowlist. The rule, the FAIL IF, scripts/loopback-lint.mjs and its self-test are all untouched.

Three edits, one concern:

  • The count says four and names the harness. The list already carried one dev-only listener (the browser-dev bridge), so a manual interop harness belongs there on the same footing.
  • The derivation says "the tracked, non-test source trees", not "the shipped trees". Two of the four are in neither shipped tree — loopback-lint reaches them only because it scans git ls-files for tracked, non-test source files — so the old instruction derives two and re-files the same miscount next time. .github/audit/application-security.md:45 repeated it verbatim to the domain that raised this, so both lines move together and the prompt now names the lint as the reference implementation.
  • The Relay is stated out of scope, once. It binds from config rather than to render a surface, and the front matter already defers the network boundary to docs/specs/security-remote.md — but nothing in the bullet said so, and the wider derivation now lands a mechanical search on relay/scripts/dev.mjs:41.

The count is the one part of that bullet nothing mechanical pins, which is why it drifted and why an auditor reading the spec instead of the tree undercounts.

docs/specs/security-local.md is at 2533 / 2550 words, so no re-baseline.

Verification

Enumerated the lint's own BIND_FORMS against git ls-files:

lib/src/host/iframe-proxy.ts:185              [node, positional]
scripts/direct-interop/run.mjs:214            [node, positional]
standalone/scripts/dev-agent-browser.mjs:223  [node, positional]
vscode-ext/src/agent-browser-host.ts:67       [node, positional]
loopback-lint: OK (4 loopback listeners, 1 allowlisted)
loopback-lint-selftest: OK (7 load-bearing checks)
public-docs-lint: 15 checks passed

scripts/spec-lint.mjs reports two pre-existing standalone/sidecar/node_modules path misses in this checkout; both are artifacts of running without pnpm install, and ci.yml is green on 6ee13512.

CI's first attempt on 7c16f6b6 went red on lib/src/host/remote/native-direct-peer.test.tslibdatachannel error while adding remote description: Got a remote candidate without ICE transport, an ICE race in a WebRTC test a one-line Markdown edit cannot reach. The rerun passed with no other change. Flagging it as one observation, not a pattern: no other ci.yml run in the last week failed this way.

Found by the 2026-09-13 nightly security audit's application-security domain (warning W1), whose report never reached audit-report.md — see #598.

Refs #598

…opback inventory

scripts/direct-interop/run.mjs binds a loopback HTTP server at :214 and has
since it landed, so loopback-lint reports four listeners while the spec's
"Loopback Listeners" section still says "Today the set is three". The harness
is guarded — it imports isOwnOrigin from lib/src/host/loopback-guard.ts and
isAuthorized from standalone/scripts/dev-host-guard.mjs — so the lint is green
and only the spec's own inventory is stale. Nothing else changes: the rule, the
FAIL IF, and the lint are all untouched.

Found by the 2026-09-13 nightly security audit (W1, refs #598).
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 13, 2026

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6fa9f90
Status: ✅  Deploy successful!
Preview URL: https://92d0bc65.mouseterm.pages.dev
Branch Preview URL: https://fix-loopback-inventory-fourt.mouseterm.pages.dev

View logs

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback on work in progress, not a merge verdict — mark the PR ready when you want the full review.

The correction itself checks out: scripts/direct-interop/run.mjs binds server.listen(0, '127.0.0.1', …), imports both isOwnOrigin and isAuthorized, and gates on them at the top of the handler, so it passes the lint by reference rather than by allowlist. loopback-lint reports 4 loopback listeners, 1 allowlisted and its self-test stays green at 7 load-bearing checks; the two spec-lint path misses are the standalone/sidecar/node_modules artifacts of an un-installed checkout, not this diff.

One thing keeps the fix from holding: the sentence's derivation instruction still says "shipped trees", which is a narrower scope than the four it now counts, and .github/audit/application-security.md repeats that instruction to the very domain that raised W1. Inline suggestion below.

One case the wider scope surfaces and this bullet doesn't address either way: relay/scripts/dev.mjs defaults DORMOUSE_BIND_HOST to 127.0.0.1 and calls server.listen(port, env.DORMOUSE_BIND_HOST), a loopback HTTP-and-WebSocket bind the regex can't see because the host is a runtime value — the case the lint's header names as its own ceiling. The front matter defers the network boundary to docs/specs/security-remote.md, so it may well be out of scope here, but nothing in the bullet says so, and an auditor deriving mechanically lands on it. Saying once why the relay is not in this set would stop the next derivation re-opening it.

Comment thread docs/specs/security-local.md Outdated
…e set it names

The bullet said to derive the set by searching the "shipped trees", but two of
the four listeners it now names — the browser-dev bridge and the direct-path
interop harness — are in neither shipped tree; loopback-lint reaches both only
because it scans git ls-files for tracked, non-test source files. An auditor
following the old instruction derives two and re-files the same miscount.
.github/audit/application-security.md repeated the instruction verbatim to the
domain that raised it, so both lines move together.

Also state once why the Relay is out of this set. It binds from config rather
than to render a surface, and the front matter already defers the network
boundary to docs/specs/security-remote.md — but nothing in the bullet said so,
and the wider derivation scope now lands a mechanical search on
relay/scripts/dev.mjs.

docs/specs/security-local.md: 2533 / 2550 words, no re-baseline.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant