ANVILNINE
On this page

Security

Serve artifacts from a separate origin

Uploaded HTML executes on the origin it is served from. That’s the product. Serve artifacts (/a/…) from a dedicated origin that serves nothing else. The dashboard and API set an admin session cookie; keeping artifacts on a separate origin means an uploaded page can never ride that cookie to call /api/*. Artifact responses never set the dashboard session cookie; the only cookie they set is a slug-scoped unlock cookie for gated artifacts.

Auth

Two credential types, split by who is calling:

  • Admin session. A human logs into the dashboard with a username and password, backed by a signed, HttpOnly, SameSite=Strict cookie. One admin account per instance.
  • Managed API keys. Scoped bearer tokens for machines (CLI, MCP, scripts). Named, revocable, optionally expiring. Scopes are read, publish, and full; give each client the least it needs.

The bootstrap ARTIFACTS_API_KEY is the all-scope break-glass key. Prefer minting scoped keys for daily use. Passwords are scrypt-hashed; API keys are stored as sha256 hashes with only a short prefix kept for display.

Reads and visibility

Reads under /a/ are public but gated by unguessable, non-indexed slugs, so don’t publish secrets in a public artifact. For anything sensitive, set an artifact to private (admin password) or password (a shared password). The gate covers every serve path, so ?raw=1, /source, and zip sub-assets never leak a locked artifact’s body.

Abuse resistance

The two unauthenticated credential routes (POST /api/auth/login, POST /a/:slug/unlock) are rate-limited in memory (10 failures per window per client IP, failures only), and password hashing runs off the event loop, so a burst of guesses degrades those routes instead of stalling the server. Behind a proxy or CDN, set TRUST_PROXY correctly and add an edge rate-limit rule as the primary layer.

Reporting a vulnerability

Do not open a public issue. Use GitHub private vulnerability reporting on anvilnine/artifacts or email security@anvilnine.com. The full threat model is in the repo’s SECURITY.md.

Last updated