Skip to content

Slice 15: harden the host with scoped tokens - #3

Closed
rvegajr wants to merge 1 commit into
docs/cli-first-contractfrom
feat/slice-15-host-hardening
Closed

rvegajr wants to merge 1 commit into
docs/cli-first-contractfrom
feat/slice-15-host-hardening

Conversation

@rvegajr

@rvegajr rvegajr commented Sep 29, 2026

Copy link
Copy Markdown
Member

Stacked on #2 (contract). Retarget to main after #2 merges.

Why

The power surface (raw CDP, cookies) makes a leaked host token catastrophic. The audit found two ways to leak it today:

  • Any GET / returned the token as a cookie.
  • There were no Host or Origin checks, so a DNS-rebinding page could reach the RPC.

What

  • Scoped tokens.
    • power: Bearer only, never served over HTTP.
    • safe: Perch and MCP.
    • POWER_METHODS is reserved in @tyto/protocol and disjoint from PERCH_SAFE_METHODS.
    • A safe token calling a power method gets unauthorized. Power methods themselves arrive in Slice 18.
  • Perch cookie via a one-time link. The link is valid for 5 minutes, only a GET consumes it, and it answers with a 303 to /. A bare GET / sets no cookie.
  • DNS rebinding / CSRF.
    • A Host other than 127.0.0.1:<port> or localhost:<port> gets 403.
    • A foreign Origin gets 403.
    • Auth is checked before the body is read.
  • No more repo .env writes.
    • npm start writes ~/.tyto/host.json (no token) and ~/.tyto/tokens/{power,safe} at mode 0600, atomically, and clears them on exit.
    • TYTO_HOST_TOKEN still pins the power token (e2e).
    • Removed the dead main.startHost.
  • CI green. gitleaks now allowlists the MV3 manifest's public-key prefix (RSA-2048 SPKI). That false positive had kept main red since PR Point LLM Relay at ai.noctusoft.com/v1 #1.
  • Node pin. .nvmrc (26), engine-strict, and engines: ^22.22.2 || ^24.15.0 || >=26, matching jsdom. CI's 22.23.2 satisfies it.
  • Docs. USAGE, README and .env.example describe the new token flow. They also stop claiming the host reads .env, which it never did.

Behavior change to note

The MV3 side panel (deferred) can't reach a real host: requests from chrome-extension:// are refused. It already couldn't, because the host never answered the CORS preflight. The Tier 3 e2e test stubs the host, so it's unaffected.

Tests

The Slice 15 tests were written first (packages/host/test/hardening.test.ts), plus protocol scope tests and updated out-of-the-box tests. For example, a HEAD request does not consume a Perch link was confirmed failing before the fix.

  • npm run check: 43 files, 266 tests, typecheck clean (Node 26).
  • gitleaks detect --config .gitleaks.toml --redact: no leaks.
  • npm install on Node 22.11: EBADENGINE, as intended.

Live e2e was not run locally; the nightly workflow covers it.

🤖 Generated with Claude Code

Slice 15. A bare GET / no longer hands out a token. Perch gets the safe
token through a one-time, five-minute link that sets an HttpOnly cookie.
The power token is Bearer-only and never served over HTTP.

Requests with a non-loopback Host (DNS rebinding) or a foreign Origin are
refused with 403. Credentials are checked before the body is read.
POWER_METHODS is reserved in @tyto/protocol, disjoint from the safe set; a
safe token calling one gets unauthorized.

npm start writes host.json (no token) and 0600 token files under TYTO_HOME
instead of appending a token to the repo .env, and clears them on exit.

Also: allowlist the MV3 manifest public key in gitleaks (turns main green),
pin Node to what jsdom supports with .nvmrc and engine-strict, and stop
telling operators the host reads .env.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rvegajr

rvegajr commented Sep 29, 2026

Copy link
Copy Markdown
Member Author

Closing: we chose agent-browser instead of building Tyto's own browser stack. Decision, measurements, and the CI fix are in #4. The commits stay reachable from this PR.

@rvegajr rvegajr closed this Sep 29, 2026
@rvegajr
rvegajr deleted the feat/slice-15-host-hardening branch September 29, 2026 20:01
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