Security policy
Stealth Web Search gives whoever can reach it a browser that runs on your machine, and it runs sub-agents that read untrusted web pages. Security reports are welcome.
Supported versions
| Version | Supported |
|---|---|
| 0.1.x | Yes |
| Older | No |
Fixes are made on the latest release. curl -s http://127.0.0.1:8931/healthz shows the version you run (version) and the Obscura version (obscura.version).
Reporting a vulnerability
Report vulnerabilities privately through GitHub. Do not open a public issue, discussion or pull request for them.
- Open the repository's Security tab and choose Report a vulnerability, or go straight to the private report form.
- Describe the problem and its impact, the version (the
/healthzoutput), how you run the server (Docker or npm, and any non-default settings), and the steps to reproduce it. A minimal page or script that triggers it helps most. - Leave out real secrets. Replace API keys, tokens, cookies and private addresses with placeholders, and redact logs and transcripts before you attach them: they can contain page content, typed text and URLs.
Only you and the maintainers can see the report. The maintainers follow up in the advisory.
Scope
The server is a remote-control port for a browser. Reports about these areas are in scope:
- The MCP endpoint and the dashboard. Reaching
/mcpor the dashboard without the bearer token whenAUTH_TOKENis set, getting around the Host and Origin checks (DNS-rebinding protection), or the dashboard leaking data it should redact. - The browser guards. Opening
file:orjavascript:URLs, or reaching private networks (localhost, RFC 1918 addresses,host.docker.internal) whileALLOW_PRIVATE_NETWORKisfalse, through any tool, sub-agent or script. - Prompt injection that breaks a boundary. Pages are untrusted input, and a model can be talked into things by text on a page. That on its own is a known risk (see below). It is in scope when page content makes the server do something its guards should prevent, such as reaching a blocked address, reading another browser's cookies, or escaping a sub-agent's isolated browser.
- The script sandbox. Automation scripts run in a QuickJS WebAssembly sandbox with no Node.js APIs and with memory, time and call limits. Any way for a script to reach the file system, the network, processes or the host outside the guarded
browserobject, or to get around those limits, is in scope. - Isolation between browsers. Sub-agent and script browsers seeing the shared browser's tabs or cookies, or each other's.
- Secret redaction. Passwords, cookie values or credential headers reaching logs, transcripts or the dashboard while
LOG_REDACT_SECRETSistrue. - The container. Anything that breaks the hardening in
compose.yamland theDockerfile(non-root user, read-only filesystem, dropped capabilities,no-new-privileges, the CDP port staying inside the container). - The helper scripts. For example
npm run lmstudio:setupwriting a token to a file that others can read, or the stdio bridge exposing the server.
Known limitations (not vulnerabilities)
These are documented and expected. Reports that only restate them are out of scope, but ways to make them worse than described are welcome.
- Obscura's cross-site cookie handling. Obscura v0.2.2 does not enforce Chromium's cross-site request protections: it sends
SameSite=Strict/Laxcookies on cross-site requests and treatsapplication/jsonPOSTs as simple requests (no CORS preflight). A page the agent visits can make cross-site requests that carry any cookies you gave the browser. This is an Obscura limitation: report changes to it to Obscura. - Prompt injection as such. A model can be manipulated by text on a page. Keep a human in the loop for sensitive accounts.
- The CDP socket in local development. Running the server directly (
npm run dev) exposes an unauthenticated Obscura CDP socket on127.0.0.1while it runs. The Docker image keeps it inside the container. - Settings that turn protections off. Publishing the port beyond
127.0.0.1withoutAUTH_TOKEN,ALLOW_PRIVATE_NETWORK=true, orLOG_REDACT_SECRETS=false. - Free text in logs. Task texts, the agent's notes and its transcript are logged as they are. Of the text the agent types, only values typed into password-like fields are masked.
- The health check.
/healthzanswers without the bearer token and for any Host header, because the Docker health check uses it. It shows the versions, the engine status and arguments (with proxy passwords masked), and the number of tabs and sessions. - Engine crashes. When a page crashes Obscura, the server restarts it and tells the agent its tabs were reset. Report reproducible crashes to Obscura unless they break a boundary listed above.
Hardening your deployment
A summary of the Security section of the README:
- Keep the port on
127.0.0.1, ascompose.yamlpublishes it. Do not change it to0.0.0.0unless you setAUTH_TOKENand put a TLS reverse proxy in front. - Set
AUTH_TOKENif anyone else can reach the port. It protects/mcpand the dashboard. Add reverse-proxy hostnames toALLOWED_HOSTS. - Keep
ALLOW_PRIVATE_NETWORK=falseunless the browser must open sites on your machine or LAN. - Prefer Docker over
npm run devon shared or multi-user machines. - Keep
OBSCURA_SEPARATE_ENGINE=true(the default), so sub-agent and script browsers run on a second Obscura process: a page that crashes the engine there cannot reset your browser. WithOBSCURA_STORAGE_DIRthe second process is always used, and it never sees the persisted cookies. - Do not persist sensitive logins with
OBSCURA_STORAGE_DIR, and clear cookies (browser_clear_cookies) before sending the agent to untrusted sites. - Keep
LOG_REDACT_SECRETS=true, and do not put secrets into sub-agent tasks. If you must, setAGENT_TRANSCRIPTS=false,LOG_FILE_LEVEL=warnandLOG_LEVEL=warn. - Keep API keys out of the repository:
.envandconfig/models.jsonare gitignored, andconfig/models.jsoncan read the key from an environment variable with${VAR}. - Treat every page the agent visits as untrusted, and keep a human in the loop for sensitive accounts.
More detail: Configuration, Sub-agents and Logging.