Skip to content

fix: TUI hardening — non-loopback LAN gate + assert cc_entrypoint (#115)#122

Merged
dtzp555-max merged 1 commit into
mainfrom
fix/115-tui-hardening
May 31, 2026
Merged

fix: TUI hardening — non-loopback LAN gate + assert cc_entrypoint (#115)#122
dtzp555-max merged 1 commit into
mainfrom
fix/115-tui-hardening

Conversation

@dtzp555-max

Copy link
Copy Markdown
Owner

Summary

Fixes the two TUI-mode hardening findings from the 2026-05-31 audit (#115, P2; ADR 0007).

  1. Non-loopback LAN gate — the fail-loud TUI boot refusal only matched literal 0.0.0.0; a concrete LAN IP / Tailscale 100.x / IPv6 :: slipped through (any reachable peer could drive the operator's full-filesystem claude session). New isLoopbackBind() treats only 127.0.0.0/8 / ::1 / localhost / ::ffff:127.0.0.1 as safe; the gate now trips on any non-loopback bind. OCP_TUI_ALLOW_LAN=1 escape hatch retained.
  2. Assert cc_entrypointverifyEntrypoint() was implemented + unit-tested but never wired; readTuiTranscript discarded the events, so a silent degrade to the metered sdk-cli pool (still returns text, but costs money) went undetected. readTuiTranscript now returns { text, entrypoint }; runTuiTurn passes it through; callClaudeTui logs tui_entrypoint_mismatch when configured cli mode yields a non-cli entrypoint (incl. null/unverified). callClaudeTui still returns Promise<string> → downstream unchanged.

ALIGNMENT.md

  • cli.js citation: N/A — TUI is a proxy-side execution-mode bridge (ADR 0007); this adds a local bind classifier + a non-fatal log assertion. No Anthropic operation forwarded (Rule 2).
  • No blacklisted tokens / port literals; alignment.yml passes.
  • Independent reviewer (Iron Rule 10): fresh-context opus reviewer verified isLoopbackBind via truth table (no exposed address misclassified as loopback — the dangerous direction is sound; default 127.0.0.1 still boots), the full string{text,entrypoint} contract ripple across every caller (grepped; Promise<string> preserved for singleflight/cache/completion), the mismatch logic (warns on sdk-cli AND null in cli mode, silent for auto/off, non-fatal), and ALIGNMENT N/A via a fetch/header grep. npm test181 passed, 0 failed. Verdict APPROVE WITH MINOR (process-only minors).

Closes #115.

🤖 Generated with Claude Code

Two TUI-mode findings from the 2026-05-31 audit (ADR 0007):

1. The fail-loud LAN gate refused TUI boot only when CLAUDE_BIND === "0.0.0.0",
   but binding to a concrete LAN IP, a Tailscale 100.x address, or IPv6 :: is
   equally network-exposed and slipped through — letting any reachable peer drive
   the operator's full-filesystem claude session. New isLoopbackBind() treats only
   127.0.0.0/8 / ::1 / localhost / ::ffff:127.0.0.1 as safe; the gate now trips on
   any non-loopback bind (OCP_TUI_ALLOW_LAN=1 escape hatch retained).

2. verifyEntrypoint() was implemented and unit-tested but never wired: readTuiTranscript
   discarded the events and returned only text, so a silent degrade to the metered
   sdk-cli (Agent SDK) billing pool — which still returns text but costs money — went
   undetected. readTuiTranscript now returns { text, entrypoint }; runTuiTurn passes it
   through; callClaudeTui logs a "tui_entrypoint_mismatch" warning when configured cli
   mode yields a non-cli entrypoint (including null/unverified). callClaudeTui still
   returns Promise<string>, so singleflight/cache/completion downstream is unchanged.

ALIGNMENT.md: TUI is a proxy-side execution-mode bridge (ADR 0007); this adds a local
bind classifier (startup gate) + a non-fatal log assertion of an existing classification
— no Anthropic operation forwarded, so a cli.js citation is N/A under Rule 2. No
blacklisted tokens or port literals introduced; alignment.yml passes.

Independent fresh-context reviewer (opus): APPROVE WITH MINOR (Iron Rule 10) — verified
isLoopbackBind via truth table (no exposed address misclassified as loopback — the
dangerous direction), the full string→{text,entrypoint} contract ripple across all
callers (Promise<string> preserved), the mismatch logic (warns on sdk-cli AND null in
cli mode, silent for auto/off, non-fatal), and ALIGNMENT N/A via a fetch/header grep.
Minors are process-only (this commit body; a future lib/ extraction of the test-mirrored
helper). npm test → 181 passed, 0 failed.

Closes #115.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dtzp555-max dtzp555-max merged commit aa1c65b into main May 31, 2026
5 checks passed
@dtzp555-max dtzp555-max deleted the fix/115-tui-hardening branch May 31, 2026 13:13
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.

[P2] TUI mode hardening (non-loopback LAN gate, assert cc_entrypoint)

2 participants