| Version | Supported |
|---|---|
| 1.x | Yes |
| < 1.0 | No (use latest 1.x) |
Do not open a public issue for security vulnerabilities.
Use GitHub Security Advisories to report vulnerabilities privately. This ensures the issue is not publicly visible until a fix is available.
- Description of the vulnerability and its impact
- Steps to reproduce — exact commands, configuration, and environment
- Affected component — which file/module is involved
- Severity assessment — your estimate of how critical this is
- Suggested fix — if you have one (not required)
| Stage | Target |
|---|---|
| Acknowledgment | 48 hours |
| Initial assessment | 1 week |
| Fix for critical issues | 7 days |
| Fix for high/medium issues | 30 days |
| Public disclosure | After fix is released |
We'll coordinate with you on disclosure timing. If we can't meet these timelines, we'll communicate why.
@ulpi/browse is a localhost-only tool that controls a headless Chromium browser. It's designed for AI coding agents running on developer machines or CI environments. The primary trust boundary is between the CLI user and the persistent server daemon.
- Server binds to 127.0.0.1 only — not exposed to the network
- Bearer token auth — random UUID generated per server startup, stored in
.browse/browse-server.json(mode 0o600) - No remote access by default —
BROWSE_CDP_URLis opt-in for connecting to remote Chrome instances - Credential vault — AES-256-GCM encryption for stored passwords, key auto-generated or provided via
BROWSE_ENCRYPTION_KEY
The following are security-relevant and should be reported:
- CLI arguments or selectors that escape into shell commands
jsorevalcommands bypassing the action policy when policy denies them- Crafted @ref identifiers that cause unintended code execution
- Server token bypass or prediction
- Accessing commands without valid Bearer token
- Policy enforcement bypass (
browse-policy.jsondeny rules not enforced)
- Weaknesses in the AES-256-GCM encryption implementation (
src/auth-vault.ts) - Key material exposure (encryption key readable by other users)
- Plaintext password leakage in logs, error messages, or network buffer
- Stored credentials accessible without proper file permissions
- Session IDs that escape
.browse/sessions/directory - Credential names that write outside
.browse/auth/ - Screenshot/PDF/HAR paths that overwrite arbitrary files
sanitizeName()bypass (src/sanitize.ts)
- HTTP requests reaching blocked domains despite
--allowed-domains - WebSocket/EventSource/sendBeacon connections bypassing the domain filter
data:,blob:, orjavascript:URI abuseroutecommand overriding domain filter restrictions
- Console/network buffers leaking data across sessions
- State file (pid, port, token) readable by other users
- Credential vault listing exposing passwords (should only expose metadata)
The following are not security vulnerabilities in this project:
- Playwright or Chromium vulnerabilities — report these upstream to Playwright or Chromium
- Local privilege escalation — the tool runs with the same privileges as the user; it doesn't elevate
- Denial of service against the local server — it's localhost-only and single-user by design
- Issues requiring physical access to the machine
- Social engineering — tricking a user into running malicious
browsecommands is no different from tricking them into running any shell command - AI agent misuse — the tool executes commands it receives; securing the agent's decision-making is the agent's responsibility, not ours. That said, the action policy system (
browse-policy.json) exists to let users restrict what commands agents can run.
If you're deploying @ulpi/browse in sensitive environments:
- Use the action policy — create a
browse-policy.jsonthat deniesjs,eval, and any commands your workflow doesn't need - Use domain filtering — set
--allowed-domainsto restrict which sites the browser can access - Set
BROWSE_ENCRYPTION_KEY— provide your own key instead of relying on the auto-generated one - Restrict file permissions — ensure
.browse/directory is only readable by the running user - Use sessions —
--sessionisolates browser contexts, cookies, and buffers between agents