Atrium is auth-adjacent infrastructure: it brokers control of a real Chromium between a server-side automation and a human end-user, and it exports browser cookies and Playwright storageState back to the host. We take reports about its security model seriously.
The @atriumjs/* packages are pre-1.0. We only ship fixes on the latest minor.
| Package version | Supported |
|---|---|
0.3.x |
Yes |
< 0.3 |
No |
Anything below the supported line: please upgrade before reporting, since the fix may already be in latest.
Do not open a public issue. Public disclosure before a patch ships puts every Atrium user at risk.
Use one of these channels instead:
- GitHub private vulnerability report (preferred) — https://github.com/ohmaseclaro/atrium/security/advisories/new. This routes directly to the maintainers and lets us coordinate a fix + CVE in a private fork.
- Email — security at atriumjs dot dev. Include the same information as the GitHub form.
Please include in your report:
- A description of the issue and the threat model it breaks (who attacks whom, with what access).
- A minimal reproduction or proof-of-concept. The smaller and more deterministic the repro, the faster the fix.
- The affected version(s) and commit SHAs.
- Any suggested mitigations or patches if you have them.
- Acknowledgement: within 3 business days. If you haven't heard back, please re-send through the other channel — mail occasionally falls into spam.
- Triage: within 7 days we'll tell you whether we accept the report, what severity we assign (CVSS 3.1), and a target patch date.
- Fix and disclosure: critical and high-severity issues are patched and released within 14 days of triage; medium within 30 days; low within 90 days. We coordinate disclosure with you and publish a GitHub Security Advisory naming the reporter (unless you ask to stay anonymous).
We don't run a paid bounty program yet. We'll credit you in the advisory and the release notes, and we'd love to send a thank-you note.
Atrium's stated threat model is documented in docs/remote-browser-design.md. Roughly, the surfaces we care about:
- Host ↔ API (the
@atriumjs/expressmiddleware). Tenant-scoped session authorization, the URL allowlist enforced on viewer-driven navigation, mTLS material handling, snapshot/cookie export endpoints. - API ↔ Worker dial WebSocket.
ATRIUM_WORKER_SECREThandling, timing-safe credential compare, thepublicBaseUrldefense. - Viewer ↔ API WebSocket relay. Viewer-token capability scope, allowlist filter on inbound
navigatemessages, control-transfer state machine. - Worker → Browser. Chromium launch flags, stealth defaults, passkey refusal, clipboard bridge.
- Snapshots and credentials. Cookies and
storageStatemust never leave the host-authenticated HTTP endpoints. - Default configurations under
policies.demo()and the example apps. We treat insecure defaults as bugs.
Examples of issues we'd consider in scope:
- Cross-tenant access to a session, its cookies, or its control state.
- Any way for a viewer-only token to read worker secrets, navigate outside the URL allowlist, or read another tenant's data.
- Authentication bypass on the API, worker, or relay surfaces.
- Server-side request forgery via session navigation or snapshot bootstrap.
- Memory or file-descriptor leaks reachable from a public endpoint that an attacker can use to degrade availability.
- Insecure defaults that ship in
demoPolicies()or the published Docker image.
The following are not vulnerabilities for the purposes of this policy:
- Reports against third-party sites that Atrium's worker visits. If a site you're handing the user to has its own bug, report it to that site.
- Reports requiring a malicious admin who already has the API host token. Anyone holding that token controls the system by design.
- Self-XSS in a page you yourself visit inside the remote browser. The whole point of the product is that the user types into a real browser; what they type is theirs.
- Denial of service via expensive but legitimate API usage when
AtriumPolicieslimits are not configured. Configure them (maxConcurrentSessionsPerTenant,sessionTtlMs,idleTtlMs,urlAllowlist) — see the user guide. - Missing security headers on the optional static landing page at
atriumjs.dev. The landing page is content-only and ships no Atrium machinery. Please still report them — we'll fix — but they aren't tracked as advisories. - Outdated dependencies without a demonstrated exploit path in Atrium's code. Please open a regular PR or issue for those.
Even with a clean security model, your deployment configuration carries most of the risk. The minimum we recommend before pointing real users at Atrium:
- Set
policies.urlAllowlistto the smallest set of origins your flow needs. Default-deny. - Rotate
ATRIUM_WORKER_SECRETon a schedule and on every suspected compromise. - Put the worker network behind a private VPC or a tight firewall; only the API tier should reach
ws://worker/internal/stream/:sessionId. - Set
publicBaseUrlexplicitly when running behind a reverse proxy; do not trust the requestHostheader. - Use mTLS for any host ↔ API hop that leaves your private network.
- Enable per-tenant quotas (
maxConcurrentSessionsPerTenant) and the idle / session TTL janitor. - For public demos, start from
demoPolicies()(per-IP rate limit, 3-min session TTL, URL allowlist locked to the demo flow) and add a Cloudflare WAF rule on top.
See docs/remote-browser-design.md §"Security model" for the full version.
Thanks for helping keep Atrium and its users safe.