VETO uses static API keys passed via:
X-API-Key: <key>header (preferred)Authorization: Bearer <key>header
API keys are stored as a comma-separated list in the Cloudflare Worker secret VALID_API_KEYS. They never appear in logs or responses.
Keys are managed via Wrangler:
# Set keys (overwrites current value)
wrangler secret put VALID_API_KEYS
# Enter: key-a,key-b,key-cThere is currently no per-key metadata (name, created-at, last-used). Per-key management is on the roadmap.
- Unauthenticated access to the validation endpoint
- Accidental exposure of billing logic to the public internet
- Compromised API keys — keys are static; rotate immediately if leaked
- Rate limiting — Cloudflare's built-in rate limiting is not configured in the MVP; add via Cloudflare dashboard
- Abuse/scraping — no per-key quotas in MVP; planned for v0.2
- Input size — no explicit payload size limit beyond Cloudflare's default (100 MB)
VETO is stateless. There is no database, no file system writes, no session state. The maximum blast radius of a compromise is: an attacker can run validation requests, consuming quota. No data can be exfiltrated because no data is stored.
All traffic is TLS 1.2+ enforced by Cloudflare. VETO does not operate over plain HTTP in production.
Secure headers are applied on every response:
X-Content-Type-Options: nosniffX-Frame-Options: DENYReferrer-Policy: no-referrer
Invoice payloads are:
- Received in memory on a Cloudflare Worker
- Parsed and validated against the rule set
- Immediately discarded — no writes to KV, R2, D1, or any external system
See NO_STORAGE.md for the full privacy guarantee.
To report a security vulnerability, email: security@veto.dev
Please do not open public GitHub issues for security vulnerabilities.
VETO does not process personal data beyond what is embedded in invoice fields (names, addresses). Under GDPR, validation-only processing without storage may qualify as transient processing; consult your DPO for your specific use case.