Security model

Small surface, explicit limits.

Sprag narrows the public side to one-way intake and keeps stronger protections optional by deployment. The important claim is precise: with E2E required, stored uploads are ciphertext to the server.

Public surface

Metadata, PIN, upload. No listing endpoint.

  • Uploaders can fetch page metadata.
  • Uploaders can pass a page PIN when one exists.
  • Uploaders can submit files.
  • Uploaders cannot browse, retrieve, alter, or delete submitted files.

Core protections

The trust boundary is visible.

Capability URL

The page URL is the upload capability.

Slugs are unguessable. Knowing one upload page reveals nothing about other pages or the admin area.

Streaming

Large files stay bounded.

The server enforces size limits while streaming to S3-compatible storage instead of trusting Content-Length or buffering whole files.

Admin side

Authenticated handling only.

Admin mutations use a same-site session and custom CSRF header. Downloads are attachments, not inline browser content.

Server-blind E2E

Post-quantum hybrid encryption before upload.

With E2E enabled, the admin creates or imports a page encryption identity. The public key rides on the upload page. The uploader browser encrypts file bytes and metadata locally, then uploads ciphertext and an encrypted envelope. The admin decrypts in the browser with the private key.

The current profile is ML-KEM-1024 plus P-384, HKDF-SHA-512, and AES-256-GCM. The private key must be backed up by the admin; Sprag cannot recover encrypted uploads without it.

Metadata policy

Uploader IP storage is an explicit deployment choice.

The compatibility default stores resolved uploader IPs as plaintext. Operators can switch to deterministic keyed HMAC identifiers with `IP_STORAGE_MODE=hmac-sha256` and `IP_HASH_SECRET`, or set `ANONYMOUS_INGRESS=true` for Tor-style ingress where Sprag stores no uploader IP metadata.

Less metadata improves privacy but weakens abuse response. Anonymous ingress uses coarser global or page-scoped rate limits because there is no stable uploader IP to key on.