Validate and bound the QR endpoint (B-67)
/qr/{address} is reachable without auth (the dashboard renders it with a
plain <img> tag, which cannot carry a bearer token), and it did two things
it should not: it accepted any plm1-prefixed string matching a shape regex,
without checking the bech32 checksum, and it ran qrcode.make on the event
loop — a free CPU amplifier that also stalled the scheduler and the
listener for the duration of every request.
Validation now goes through is_valid_plm_address, the same check
withdrawals and the admin fee_address validator use, behind a length guard
so an oversized path never reaches embit. The render is memoized per
address in a bounded LRU (valid addresses are cheap to generate, so an
unbounded cache would just move the amplification to memory) and pushed
off the loop with run_in_threadpool, and the response carries a
Cache-Control so a browser stops re-asking for an image that never changes.
The rejection now uses the structured error contract (invalid_address),
which already has its i18n key.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,23 +38,6 @@ remains the last prerequisite for running unattended.
|
||||
|
||||
---
|
||||
|
||||
## Medium — correctness and robustness
|
||||
|
||||
### B-67 — `/qr/{address}` is unauthenticated, synchronous and only shape-validated
|
||||
|
||||
`app/api/routes/qr.py:11-21`.
|
||||
|
||||
`qrcode.make` runs on the event loop, so the endpoint is a cheap CPU amplifier for
|
||||
an unauthenticated caller, and the regex accepts any `plm1[a-z0-9]{10,90}` string
|
||||
without validating the bech32 checksum — so it happily renders a QR for a
|
||||
non-address.
|
||||
|
||||
Fix: validate with `is_valid_plm_address` (already used by withdrawals and by the
|
||||
admin `fee_address` validator), and either offload the render or cache it per
|
||||
address.
|
||||
|
||||
---
|
||||
|
||||
## Low — documentation and consistency drift
|
||||
|
||||
### B-68 — CLAUDE.md and README describe a state the code has moved past
|
||||
|
||||
Reference in New Issue
Block a user