Security model
What the gateway defends by construction, and what remains yours to operate safely.
Serving is confined
Every directory-product read and delete goes through one guard (resolveSafe): realpath containment (catches ../ traversal and symlinks pointing out of the folder), a deny on any dot-segment (.env, .git/…), and a deny on secret extensions (*.env, *.key, *.pem). Uploads pass the same rules, with path components stripped from filenames. Structural separation is the primary wall: secrets live in the app root, content in its own subtree — the gateway never serves its own root.
Money-path invariants
- 404 before 402 — a buyer can never pay for a missing file
- Every settlement writes synchronously with a unique tx hash (no double-count); every paid request row links to it — the reconciliation invariant: every 200 served = exactly one on-chain transfer
- Demand-pricing floor/ceiling bound what any traffic manipulation can achieve
- No hot key on the server — the gateway holds only your receiving address; nothing on the box can spend funds
Privacy
Raw client IPs are never stored — only a salted hash. Full payer addresses (pseudonymous but linkable) appear only behind admin auth; the public feed truncates them to 0x1234…abcd. The per-hit request log is pruned automatically after RETENTION_DAYS (default 90); the settlements ledger is permanent.
Admin brute-force lockout
Five failed logins from one source lock it out for 15 minutes (even with the correct password), per-IP, audit-logged, reset on success.
Config integrity
All catalog and settings writes are validated-before-write, atomic (temp file + rename), and audited to the journal ([admin-audit] lines). A changed payTo you didn't make is an incident, not an edit — it redirects revenue silently.
Your side of the contract
- Strong
ADMIN_PASSWORD(≥12 enforced); keep/adminoff any public tunnel .envstays 0600 and out of git (scaffolded that way)- Mainnet
payTois a self-custody address whose keys never touch this machine