Skip to content

fix(transport): exempt loopback hosts from MISSING_TLS / INSECURE_TRANSPORT (#48)#53

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-tz5o4d
Open

fix(transport): exempt loopback hosts from MISSING_TLS / INSECURE_TRANSPORT (#48)#53
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-tz5o4d

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Summary

Fixes #48. MISSING_TLS and INSECURE_TRANSPORT keyed purely off the URL scheme, ignoring the host, so any plaintext http:// or ws:// transport bound to a loopback address (localhost, 127.0.0.0/8, ::1) earned a HIGH finding.

Loopback traffic never leaves the machine — there is no network segment on which it could be intercepted — so:

  • The finding's "all traffic … is sent in cleartext over the network" claim is factually wrong for loopback.
  • Under --fail-on=high / --exit-code (the tool's own CI-gate recommendation), a fully-secured local dev server failed the build — and http://localhost is the dominant deployment for MCP servers (Claude Desktop, Cursor, VS Code, Windsurf all launch servers locally).

This implements Option A from the issue (the maintainer-recommended direction), mirroring the W3C Secure Contexts spec, which classifies localhost, 127.0.0.0/8, and ::1 as potentially trustworthy.

Changes

  • src/rules/loopback.ts (new): isLoopbackHost(url) helper — parses the host via the URL API and matches localhost / *.localhost (RFC 6761), 127.0.0.0/8, ::1, and 0.0.0.0. Returns false for unparseable URLs and lookalike hosts (e.g. localhost.evil.com).
  • src/rules/auth-rules.ts (MISSING_TLS) and src/rules/runtime-rules.ts (INSECURE_TRANSPORT): skip the finding when the transport URL is loopback.
  • src/__tests__/scanner.test.ts: loopback vs. public vs. lookalike coverage for both rules, plus an end-to-end secure-loopback scan asserting passed: true and zero HIGH findings.
  • CHANGELOG.md: documents the fix under [Unreleased] → Fixed.

Behavior (built CLI)

# Secure loopback dev config — now PASSES (was a false HIGH → FAILED)
$ node dist/cli.js loopback.json --fail-on=high ; echo "exit=$?"
Found 0 finding(s)
PASSED
exit=0

# Public http:// — still fires HIGH (no regression)
$ node dist/cli.js public.json --fail-on=high ; echo "exit=$?"
HIGH | MISSING_TLS | Missing TLS — Server Uses Plain HTTP
FAILED
exit=1

Acceptance criteria (from #48)

  • Loopback http://localhost / http://127.0.0.1 / http://[::1] does not produce a HIGH MISSING_TLS.
  • Loopback ws://localhost is handled the same way for INSECURE_TRANSPORT.
  • Non-loopback http:// / ws:// still fire HIGH; https:// / wss:// still pass (no regression).
  • Tests covering loopback vs. public hosts for both rules.

Verification

  • npm run typecheck — clean
  • npm run lint — clean (--max-warnings 0)
  • npm test — 131 passed (10 new)

🤖 Generated with Claude Code

https://claude.ai/code/session_013wetiH1LxF572ZPsudYYrW


Generated by Claude Code

…NSPORT (#48)

MISSING_TLS and INSECURE_TRANSPORT keyed purely off the URL scheme, so any
plaintext http:// or ws:// transport bound to a loopback host (localhost,
127.0.0.0/8, ::1) earned a HIGH finding. Loopback traffic never leaves the
machine, so there is no network segment on which it could be intercepted —
the finding text's "sent in cleartext over the network" claim is factually
wrong for loopback, and under --fail-on=high / --exit-code it failed the
build on the most common local-dev MCP setup (Claude Desktop, Cursor,
VS Code, Windsurf all launch servers on http://localhost).

Add an isLoopbackHost() helper (localhost and *.localhost, 127.0.0.0/8, ::1,
0.0.0.0) and guard both rules with it, mirroring the W3C Secure Contexts
"potentially trustworthy" carve-out. Non-loopback http:// / ws:// URLs still
fire HIGH; https:// / wss:// still pass. Adds tests covering loopback vs.
public and lookalike hosts for both rules plus an end-to-end secure-loopback
scan, and documents the change in CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013wetiH1LxF572ZPsudYYrW
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants