"Quis custodiet ipsos custodes?" applies to anything that spends your money on a button press. Read this before exposing the app anywhere.
This app places real, money-costing orders on an unauthenticated button press. The only safety rails are a browser confirm dialog and the fact that payment is cash-at-pickup (no stored card to drain).
- No card data. Ever. Payment type is hardcoded
Cash. There is no field, variable, or code path that accepts, stores, or transmits a card number, CVV, or expiry. If you ever want card payment, that is a deliberate redesign with its own security review — not a config tweak. - No login / no auth. Anyone who can reach port 5000 can order a pizza on your dime. This is acceptable ONLY because the app is bound to a private LXC on your home network / tailnet.
- DO keep it on the LAN or tailnet (
100.x/10.x). Reach it over Tailscale, not the public internet. - DO NOT put it behind Funnel, a public reverse proxy, or any internet-facing route. A single curl from a stranger = a pizza you didn't order and have to refuse at the counter.
- If you ever need remote access, gate it behind Tailscale ACLs, not exposure.
- None. There are no API keys, tokens, or passwords. The unofficial Domino's API requires no authentication — that is precisely why guarding network exposure matters.
config.pycontains your name, email, phone, and address in plaintext. This is necessary for the order and is no more sensitive than a saved Domino's profile — but it meansconfig.pyshould not be committed to a public repo. Keep the repo private, or templateconfig.pyand gitignore the real one. (Currently committed for the POC; the repo is assumed private.)
- The confirm dialog is the last line before a real order. The
/orderroute has no rate limit — repeated POSTs place repeated orders. Don't script against it. /dryrunis safe to hammer; it never places.
- systemd unit runs as unprivileged
stimpyuser withNoNewPrivileges,ProtectSystem=strict,ProtectHome,PrivateTmp.
Customer identity (name, address, phone, email) lives in config_local.py, which is gitignored. The repo tracks config_local.example.py with placeholder values only. Commits before 2026-08-05 predate this split and contain the old hardcoded identity; the repo is private and stays private unless history is rewritten.