Settlement loop has no per-payment error isolation; a malformed zap request drops webhooks and zaps for other paylinks #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
wait_for_paid_invoices(tasks.py:20-22) awaitson_invoice_paidinsidewhile Truewith no try/except.send_zap(tasks.py:111-139) doesjson.loads(nostr)andassert pubkeyon data that comes straight from the public LNURL callback's?nostr=query parameter (views_lnurl.py:97-99, stored verbatim). Any payer of any zaps-enabled link can therefore make the shared listener raise after their invoice settles. lnbits core restarts the task after 5 s (catch_everything_and_restart), but the restart re-registers a fresh invoice queue, so the triggering payment's webhook and any payments queued behind it are lost — including plain (non-zap) webhook deliveries for unrelated tenants' links. The attacker controls timing and can repeat at will for the cost of a minimum-amount payment.Fix direction: wrap the per-payment body in
wait_for_paid_invoicesin try/except (log and continue); makesend_zapdefensive (guardjson.loads, early-return instead ofassert); ideally reject malformed zap requests at the callback before creating the invoice (see sandbox lnurlp#3). Regression test: enqueue a payment withextra["nostr"] = "not json"followed by a valid one and assert the second still fires its webhook.Found during reforge run #1 (sandbox lnurlp#4).
webhook_urlis unvalidated: server-side POST with attacker-chosen headers to any host (SSRF) #2