xpay: print rejected currency correctly.
What changed, and why it matters
This commit fixes a minor bug in Core Lightning's xpay plugin where an error message about unsupported foreign-currency offers could print garbage or truncated text instead of the actual currency code (like 'USD'). It is a correctness and usability fix, not a security vulnerability.
No security action required; treat as a normal bug-fix/correctness patch. Reviewers may optionally verify the regression test passes.
Security signals we found
No security-relevant signal: bug is a format-string/correctness issue for a user-facing error message
No memory corruption or privilege escalation path identified
Error path is reached only when the offer already cannot be paid
Evidence from the diff
The change replaces two printf-style ‘%s’ format specifiers with ‘%.*s’ plus an explicit byte length (tal_bytelen) for b12offer->offer_currency in command_fail() error strings. The offer_currency field is not a NUL-terminated C string, so ‘%s’ could read past the buffer or stop early, producing malformed output. The patch also adds a regression test verifying that ‘USD’ is reported correctly for both xpay and sendamount.
Changed components
plugins/xpay/xpay.ctests/test_xpay.pyInspect captured patch +19 / −2
diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c
index 6a0ff309..8510c596 100644
--- a/plugins/xpay/xpay.c
+++ b/plugins/xpay/xpay.c
@@ -2153,7 +2153,8 @@ static struct command_result *check_offer_payable(struct command *cmd,
/* We will only one-shot if we know amount! (FIXME: Convert!) */
if (b12offer->offer_currency)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
- "Cannot pay offer in different currency %s",
+ "Cannot pay offer in different currency %.*s",
+ (int)tal_bytelen(b12offer->offer_currency),
b12offer->offer_currency);
if (b12offer->offer_amount) {
if (msat && !amount_msat_eq(amount_msat(*b12offer->offer_amount), *msat)) {
@@ -2188,7 +2189,8 @@ check_offer_sendamount_payable(struct command *cmd, const char *offerstr)
/* FIXME: add currency support */
if (b12offer->offer_currency)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
- "Cannot pay offer in different currency %s",
+ "Cannot pay offer in different currency %.*s",
+ (int)tal_bytelen(b12offer->offer_currency),
b12offer->offer_currency);
/* Can only be applied to *any amount* offers. */
if (b12offer->offer_amount)
diff --git a/tests/test_xpay.py b/tests/test_xpay.py
index c419589e..0f8475bc 100644
--- a/tests/test_xpay.py
+++ b/tests/test_xpay.py
@@ -975,6 +975,21 @@ def test_xpay_offer(node_factory):
l1.rpc.xpay(offer2, 5000)
+def test_xpay_currency_offer(node_factory):
+ """Test that xpay and sendamount correctly report the currency name when rejecting non-msat offers."""
+ plugin = Path(__file__).parent / "plugins" / "currencyUSDAUD5000.py"
+ l1, l2 = node_factory.line_graph(2, wait_for_announce=True,
+ opts=[{}, {'plugin': str(plugin)}])
+
+ offerusd = l2.rpc.offer('10USD', 'USD test')['bolt12']
+
+ with pytest.raises(RpcError, match=r"Cannot pay offer in different currency USD"):
+ l1.rpc.xpay(offerusd)
+
+ with pytest.raises(RpcError, match=r"Cannot pay offer in different currency USD"):
+ l1.rpc.sendamount(offerusd, '100sat')
+
+
def test_xpay_bip353(node_factory):
fakebip353_plugin = Path(__file__).parent / "plugins" / "fakebip353.py"
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.