T09 · Insecure Skill Coding Practices
Error
- Location
- escrow-integration.js:41
- Finding
- Escrow Release Accepts Fabricated Proof Hashes<![CDATA[ ## Vulnerability Details **File Location**: `escrow-integration.js:41-60` **Vulnerability Type**: Insufficient cryptographic proof verification **Risk Level**: High ### Vulnerable Code ```javascript export async function releaseOnProof(escrowClient, escrowId, proofHash, orderData) { console.log(`Verifying proof: ${proofHash}`); // Verify proof matches expected format if (!proofHash.startsWith('0x') || proofHash.length !== 66) { throw new Error('Invalid proof hash format'); } // Verify order data is complete if (!orderData.orderId || !orderData.total) { throw new Error('Incomplete order data'); } console.log(`✓ Proof verified`); console.log(`Order ID: ${orderData.orderId}`); console.log(`Total: $${orderData.total}`); // Release escrow console.log(`Releasing escrow: ${escrowId}`); await escrowClient.escrowRelease(escrowId); console.log(`✓ Escrow released`); return true; } ``` ### Technical Analysis The function labels a proof as verified after checking only that: 1. The value begins with `0x`. 2. Its total length is 66 characters. 3. The supplied order object contains truthy `orderId` and `total` properties. It does not verify that the remaining 64 characters are hexadecimal, recompute the expected SHA-256 hash, compare the supplied proof with trusted evidence, validate that the order belongs to the escrow, or obtain an authenticated purchase or delivery confirmation. Consequently, a string such as `0x` followed by any 64 arbitrary characters satisfies the proof check. The caller also controls the order data used by the presence check. ### Attack Path 1. An attacker or compromised purchase callback identifies an active escrow ID. 2. The attacker constructs an arbitrary 66-character value beginning with `0x`. 3. The attacker supplies invented but truthy values for `orderData.orderId` and `orderData.total`. 4. `releaseOnProof()` reports the proof as verified. 5. The function invokes `escrowClien ...[truncated 612 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Recompute the expected proof from canonical, validated order data and immutable purchase evidence. - Compare the supplied and expected hashes using `crypto.timingSafeEqual()` after strict hexadecimal decoding. - Validate the proof with a trusted retailer receipt, payment-provider record, or authenticated fulfillment attestation rather than caller-controlled fields alone. - Bind the proof to the escrow ID, expected recipient, authorized budget, currency, retailer, order ID, and nonce. - Retrieve escrow expectations from trusted storage instead of accepting all verification inputs from the caller. - Require delivery confirmation if release is intended to occur only after delivery. - Enforce a strict proof schema and reject non-hexadecimal or malformed values. - Record proof verification and release as an atomic, idempotent state transition to prevent replay. ]]>
