Skip to content

fix: keep Playwright MCP on loopback, no tailnet mapping (#115) - #116

Merged
chaodu-agent merged 3 commits into
mainfrom
fix/pw-mcp-no-tailnet-exposure
Nov 14, 2026
Merged

chaodu-agent merged 3 commits into
mainfrom
fix/pw-mcp-no-tailnet-exposure

Conversation

@chaodu-agent

@chaodu-agent chaodu-agent commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #115

What changed and why

poc/pw-mcp/install.sh mapped the unauthenticated Playwright MCP onto the tailnet (:8443), bypassing oab-instance-mcp's login check, bearer token, owner-only profile and any switchboard allowlist. Now:

  • install.sh creates no tailscale serve mapping and prints no MCP URL. Header comment fixed. The LaunchAgent stays.
  • Loopback: pw-mcp.sh already passes --host 127.0.0.1 --port 8794 and the plist runs only that wrapper, so it binds loopback only. No change needed. The unused <host>.<tailnet>.ts.net:8443 entry was dropped from --allowed-hosts (oab-instance-mcp sends the bare 127.0.0.1).
  • New poc/pw-mcp/check-legacy-mapping.sh (sourced by install.sh): read-only tailscale serve status (with TERM_PROGRAM=oab-pw-mcp-installer, only if the CLI is found). If :8443 maps to 127.0.0.1:8794, it warns and prints tailscale serve --https=8443 off. It never runs a mutating serve command, never fails the install, and prints "could not check" when the CLI is missing or the status is unreadable. It prints no login, tailnet name or token.
  • install.sh ends with one line on using browser tools through oab-instance-mcp --upstream browser=http://127.0.0.1:8794/mcp.
  • Docs: poc/pw-mcp/README.md and the main README ("Network interfaces and ports", the diagram, Exposing it, What the menu shows) now say 8794 is loopback only, reached only through oab-instance-mcp, no :8443 path, plus the check and removal commands for older installs.
  • CI: new job pw-mcp-loopback runs shellcheck and scripts/test-pw-mcp-check.sh. The guard joins backslash continuations and fails on any tailscale/$VAR serve call in non-markdown files under poc/pw-mcp/ (any port or variable), after cutting out serve status and serve --https=8443 off; comments and README prose are not scanned.

Remediation for existing installs

Re-running the installer does not remove an old mapping. On each Mac that ran the old installer: tailscale serve status, and if :8443 maps to 127.0.0.1:8794, tailscale serve --https=8443 off. Browser tools keep working through oab-instance-mcp over loopback.

Verification (stub CLI only; no real tailscale)

  • bash -n on the three scripts: OK. shellcheck 0.11.0 -x --source-path=SCRIPTDIR on the three scripts: clean (same flags in CI).
  • Guard negatives all fail: split-line call, same-line hide after serve status, variable port, old install.sh. Allowed-only file passes.
  • scripts/test-pw-mcp-check.sh: guard ok on the fix; stub cases: mapping present -> warning with the removal command; absent -> "no mapping ... found"; unreadable -> "could not check (serve status unreadable)"; CLI missing -> "could not check (Tailscale CLI not found)". Output never contains the stub host name.
  • The guard fails on the old install.sh (git show origin/main:poc/pw-mcp/install.sh): install.sh:36: "$TS" serve --bg --https=8443 http://127.0.0.1:8794, exit 1.
  • grep: the only serve calls in poc/pw-mcp/*.sh are serve status and the quoted warning text.
  • Markdown lint: CI lints docs/**/*.md only; no docs/ file changed and docs/ has no 8443. The READMEs are outside that scope. The linter was not run locally.

Not verified

install.sh was not run on a Mac. No mapping was removed from any Mac. The real tailscale serve status text was not observed (the parse assumes an unindented https://...:8443 header followed by handler lines).

Update (48909cf): the CI guard now rejects an executed serve --https=8443 off and funnel calls; only the warning heredoc text is exempt. Checked against the fix (pass) and four bad cases (fail).

- install.sh no longer runs tailscale serve --https=8443 or prints an MCP URL
- read-only check (tailscale serve status) warns if an old :8443 mapping exists
- docs (poc/pw-mcp/README.md, README.md) drop :8443 as an access path
- CI job pw-mcp-loopback: guard for serve calls to 8794/8443 + stub-CLI tests

Verified: bash -n ok; scripts/test-pw-mcp-check.sh passes (guard ok; stub cases
present/absent/unreadable/missing print warning/no mapping/could not check x2);
guard fails on the old install.sh. shellcheck and markdownlint not run locally
(not installed); docs/ untouched. Not run on a Mac.
- shellcheck -x --source-path=SCRIPTDIR; SC2034 disabled where $TS is read by the sourced function (SC1091/SC2034 fixed).
- Guard joins backslash continuations, cuts allowed forms (serve status, serve --https=8443 off) before matching, and flags ANY `tailscale|$VAR serve` call in non-md files under poc/pw-mcp (so variable ports are caught too).
- pw-mcp.sh: drop the unused $DNSNAME:8443 from --allowed-hosts (oab-instance-mcp sends bare 127.0.0.1).

Ran: bash -n ok; shellcheck 0.11.0 -x --source-path=SCRIPTDIR on 3 scripts: clean; scripts/test-pw-mcp-check.sh: guard ok + 4 stub cases ok; negatives (split line, same-line hide, variable port, old install.sh) all fail the guard, allowed-only file passes.
#115)

Heredoc body of the MSG warning is the only exemption. Ran: bash -n ok; shellcheck not installed; scripts/test-pw-mcp-check.sh passes (4 stub cases); guard fails on appended '"$TS" serve --https=8443 off', tailscale serve 8443 and funnel, and on the old install.sh.
@chaodu-agent
chaodu-agent merged commit 1eaa6ef into main Nov 14, 2026
11 of 12 checks passed
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.

pw-mcp installer exposes unauthenticated Playwright MCP to the whole tailnet on :8443; keep it behind oab-instance-mcp

1 participant