Skip to content

NUT-14 HTLC refund path incorrectly requires preimage (spec violation) #848

@Amperstrand

Description

@Amperstrand

Summary

NUT-14 HTLC refund path requires a preimage even after locktime has passed. The spec says only a signature is needed.

Bug Location

cashu/core/nuts/nut14.py lines 24-27:

if not proof.htlcpreimage:
    raise TransactionError("no HTLC preimage provided")  # Checked BEFORE locktime
now = time.time()
if not htlc_secret.locktime or htlc_secret.locktime > now:  # Locktime check comes AFTER

The preimage check is unconditional but should only apply before locktime.

Expected vs Actual

Test Expected Actual
Refund with signature only (per spec) ACCEPT REJECT
Refund with dummy preimage N/A ACCEPT

Proof of Concept

https://gist.github.com/Amperstrand/3cc9788f1bac4c1461e441bfa1ef47eb

Run: npx tsx nutshell_htlc_bug_e2e.ts

Fix

def verify_htlc_spending_conditions(proof: Proof) -> bool:
    # ...
    now = time.time()
    
    # Refund path: locktime passed, only signature needed
    if htlc_secret.locktime and htlc_secret.locktime < now:
        return True
    
    # Hashlock path: require preimage
    if not proof.htlcpreimage:
        raise TransactionError("no HTLC preimage provided")
    # ...

Note

Existing HTLC tests always include a preimage in refund scenarios, so this wasn't caught.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions