Destination proofs do not bind datums for script payment addresses
Description. The destination-bound ownership proof commits to the affected credential and the 58-byte destination-address-v1 encoding, but not to the destination output’s datum or reference script (circuit.go:57-70):
preimage = append(preimage, domain...)
preimage = append(preimage, credential[:]...)
preimage = append(preimage, destination[:]...)
digest := hash.Blake2b(api, uapi, preimage, 32)
Correspondingly, ReclaimGlobalV2 reconstructs the destination from the output’s address field alone (ReclaimGlobalV2.hs:376-382) and checks its value and proof without inspecting the datum (ReclaimGlobalV2.hs:575-611). A valid proof therefore remains valid if a transaction builder keeps the same destination address and value but substitutes the datum while constructing the recovery output.
This matters only for a script payment address whose spending rules use the datum to select a beneficiary or other spending authority. The refund frontend accepts enterprise addresses as destinations (destinationAddressV1.ts:137-145) and encodes a script payment credential using tag 0x02 (destinationAddressV1.ts:173-184).
A datum already attached to an existing UTxO cannot be modified. The substitution described here occurs before the recovery output is created.
Impact. Key payment destinations are unaffected. Exploitation requires a script payment destination whose spending authority depends on its datum, plus control over transaction construction and access to the valid ownership proof. Under these narrow conditions, changing the datum could redirect control of the recovered output.
Recommendation. Reject script payment credentials in the refund frontend before generating a proof or submitting a claim. This should match proof-tool’s existing assertSafeWalletAddress check, which permits only key payment credentials (addresses.ts:56-64). Apply the same restriction in the claims backend so custom clients cannot bypass the frontend check.
Client Response. The client has acknowledged the finding and has implemented a fix in the refund repository. The audit team has reviewed the diff, retested and confirmed the fix is valid.