Skip to content

feat(security): add host origin allowlist on start - #170

Open
yashranaway wants to merge 2 commits into
mainfrom
feat/navigation-allowlist
Open

feat(security): add host origin allowlist on start#170
yashranaway wants to merge 2 commits into
mainfrom
feat/navigation-allowlist

Conversation

@yashranaway

Copy link
Copy Markdown
Collaborator

Summary

Adds a host-enforced origin allowlist so a prompt-injected agent cannot leave the app under test. headless start --allow PATTERN restricts visit, top-frame navigation, and in-page clicks; omitting --allow keeps today's unrestricted HTTP(S) behavior.

Contract

headless start [--background|--foreground] [--allow PATTERN]...
headless start --allow localhost --allow '*.staging.example.com'
headless start --allow localhost,127.0.0.1
  • Repeatable --allow; comma-separated values in one flag also accepted.
  • Presentation flags stay macOS-only.
  • Still HTTP/HTTPS only. --allow cannot add file:, javascript:, credentials, or blocked extensions. normalizedWebURL is unchanged; the allowlist is an extra conjunct in agentMayNavigate.
  • Empty --allow is a parse error. * alone, paths, schemes, credentials, non-ASCII, and unexpected characters fail closed. Cap 32 patterns; case-insensitive DNS; IPv4 literals as exact hosts.
  • *.example.com matches subdomains, not the apex, and not example.com.evil.test.
  • localhost matches any port; localhost:3000 matches only that port.
  • When set, a non-matching host fails with UNSAFE_NAVIGATION.
  • status / ping includes navigationAllowlist (empty array means unrestricted).
  • Changing the list on a running host is rejected (NAVIGATION_ALLOWLIST_CONFLICT — stop first). Matching list or start without --allow against a running host is a no-op.
  • CLI sets HEADLESS_NAVIGATION_ALLOWLIST on the spawned host. The injected runtime gets a JSON-encoded copy as defense in depth; host policy is authoritative.
  • Protocol version stays 0.5 (additive ping field). Architecture decision 22.

Tests

  • Protocol suite: parse (repeated, comma-separated, with presentation flags), reject * / schemes / credentials / empty --allow / too many patterns, matcher (wildcard non-match, apex vs subdomain, port exactness, unrestricted when empty), visit still validates example.com as a URL, host-side deny via agentMayNavigate, ping reports the list.
  • Agent runtime: click guard honors __headlessNavigationAllowlist.
  • Linux E2E: stop, start --allow 127.0.0.1, fixture visit OK, https://example.com and off-list click fail UNSAFE_NAVIGATION, mismatch requires stop, restore unrestricted host.
  • macOS E2E: matching restart block.

pnpm test:runtime passed. Local pnpm test cannot run Swift on this Linux box (exit 69); the Linux Docker builder ran 46/46 protocol tests and Linux P2 E2E passed, including the new allowlist block.

Review

@SarthakWade please review before morning.

Closes #167

Restrict agent navigation with repeatable `headless start --allow PATTERN`.
The matcher is an extra conjunct in agentMayNavigate; ping reports the
active list, and changing it on a running host requires stop first.
@yashranaway yashranaway self-assigned this Sep 10, 2026
@yashranaway

Copy link
Copy Markdown
Collaborator Author

Please review this one first. #169 (file upload) was branched from the same main and will need a rebase after this merges. They share CLI/protocol/docs files but the allowlist contract does not depend on upload.

@yashranaway

Copy link
Copy Markdown
Collaborator Author

macOS CI failed on the runner SDK, not the allowlist: no macOS SDK compatible with the installed Swift compiler. Linux protocol + E2E are green. Reran the failed job.

agentMayNavigate now references NavigationAllowlist. The macOS SDK
selection typechecks Protocol.swift in isolation, so every SDK looked
incompatible and CI reported a missing toolchain.
@yashranaway

Copy link
Copy Markdown
Collaborator Author

The macOS failure was the SDK probe, not the runner. build.sh typechecks Protocol.swift alone to pick an SDK. agentMayNavigate now references NavigationAllowlist, so every SDK failed that probe and the script said the toolchain was missing. Probe now includes NavigationAllowlist.swift.

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.

Host origin allowlist on start

1 participant