From 7727b97c71c11b4b65f47bcc68460ea981c1b22c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 6 Oct 2026 15:53:18 -0700 Subject: invoices: a supplied account must belong to the invoice's user generate() took any existing account id as the credit target, so an invoice could carry one user's name while paying into someone else's account. A supplied aid now has to be in the invoice user's own account list; otherwise the invoice credits that user's main account. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KCxLg8s1g8yBwjRwPN4uJR --- lib/invoices.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/invoices.ts b/lib/invoices.ts index 7f25f4ba..c4e6a131 100644 --- a/lib/invoices.ts +++ b/lib/invoices.ts @@ -57,7 +57,12 @@ export const generate = async ({ invoice, user }) => { if (!user) fail("user not provided"); if (typeof prompt === "undefined") prompt = user.prompt; - let account = await g(`account:${aid}`); + // The invoice shows `user`'s name but credits `aid`, so a supplied aid must + // be one of that user's own accounts — otherwise anyone could put a + // merchant's name on an invoice that pays their own account. + if (aid && aid !== user.id && (await db.lPos(`${user.id}:accounts`, aid)) === null) + aid = undefined; + let account = aid ? await g(`account:${aid}`) : null; if (!account) account = await g(`account:${user.id}`); if (!account) fail("account not found"); aid = account.id; -- cgit v1.2.3