audit: constructProofs binds neither signature amount nor keyset id to the wallet's request — tampered/hostile swap responses mint-label the proofs (PoC reproduced; fix lands in gonuts-tollgate)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 12/100
Research direction
The bug lives in the forked wallet's constructProofs (around wallet/wallet.go:2076-2121, in gonuts-tollgate, not this repo), which is where the signature amount and keyset id are trusted instead of checked against the blinded message request. Start by reading that function and the in-package PoC reusing pending_swaps_test.go fixtures. Done means each signature's Amount and Id are checked against the request per index, the unblinded C is verified against Y, and a test covers the tampered-amount case.
Written by the indexing model from the issue text.
Description
From the 2026-10-09 Cashu audit (fork @ d7591d2 + main + #771). PoC reproduced in-package. Fix belongs in gonuts-tollgate (fork-first, then pin bump — the fork repo has issues disabled, tracked here per the #705 pattern).
Finding
Fork wallet/wallet.go constructProofs (≈:2076-2121) accepts whatever BlindSignature.Amount/.Id the response carries: the unblind key is selected BY the signature's own amount label — never compared against blindedMessages[i].Amount/.Id (what the wallet actually requested) — the proof is mint-labeled, there is no post-unblind C-vs-Y verification, and a stripped (nil) DLEQ is skipped silently (so DLEQ presence does not close this).
Attack path
MITM on an http:// mint URL (cloud-lab topology uses one; config does not forbid it) or a malicious mint relabels one signature in a /v1/swap response. Receive returns newProofs.Amount() — the mint-labeled sum — straight into calculateAllotment (merchant.go:2069), which sizes the customer's session; the ecash path has no amount ceiling (the ln-invoice path caps at maxLightningInvoiceSats; steps*StepSize is unbounded here). Also applies to the #771/#497 replay path (resumeOneSwap → same constructProofs).
PoC (in-package, reusing pending_swaps_test.go fixtures)
request 8 sat of outputs → stub mint signs honestly → tampered[0].Amount = 64
constructProofs(tampered, outputs, secrets, rs, keyset) → err=nil, proofs.Amount()=71
Impact: inflated labels → oversized sessions (repeatable revenue theft); deflated → silent under-credit; garbage proofs pollute balance accounting. CWE-345/CWE-347. Severity MEDIUM (preconditions: http-mint MITM or hostile mint).
Minimal fix
constructProofs must require sig.Amount == msg.Amount && sig.Id == msg.Id per index and verify the unblinded C against Y under the selected key; consider refusing stripped DLEQ on keysets that announced it.
Cross-refs: #703, #497, #771.
- Dominant language
- Go
- Stars
- 12
- Forks
- 14
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 239
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from OpenTollGate/tollgate-module-basic-go
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
OpenTollGate/tollgate-module-basic-go#833 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
OpenTollGate/tollgate-module-basic-go#813 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
OpenTollGate/tollgate-module-basic-go#804 ·
Maintainers usually reply within 1 day
-
go-battery needs an ndsctl on PATH: TestPurchaseSessionGuardHoldsThroughTheOutcomeUnknownWindow fails on bare hosts (passes with stub)Possibly taken @Amperstrand claimed this 1 day ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
OpenTollGate/tollgate-module-basic-go#726 · 2 comments ·
Maintainers usually reply within 1 day
-
rebrand-literal-gutter: uhttpd section-vocabulary check trips on a COMMENT (uhttpd.luci in 92-tollgate-admin-setup:178)Possibly taken @Amperstrand claimed this 1 day ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
OpenTollGate/tollgate-module-basic-go#723 ·
Maintainers usually reply within 1 day
All issues in OpenTollGate/tollgate-module-basic-go
Similar issues
-
documentation
Difficulty 1/5 Under an hour Newbie friendliness 85/100
gravitational/teleport#69869 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 63/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100