{"record":{"id":"43a81e1d9e008fe7","repo":"linera-io/linera-protocol","slug":"receipt-payload-extends-past-available-data","errorCode":null,"errorMessage":"receipt payload extends past available data","messagePattern":"receipt payload extends past available data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-bridge/src/proof/mod.rs","lineNumber":389,"sourceCode":"/// with multiple receipts (e.g. test_build_receipt_proof_multiple_receipts),\n/// each receipt needs a distinct cumulative_gas_used to produce different\n/// RLP encodings. Without that, all empty-log receipts would be byte-identical,\n/// making the trie degenerate.\npub fn decode_receipt_logs(receipt_rlp: &[u8]) -> Result<Vec<ReceiptLog>> {\n    ensure!(!receipt_rlp.is_empty(), \"empty receipt RLP\");\n\n    let mut data: &[u8] = receipt_rlp;\n    // EIP-2718: if first byte < 0x80, it's a transaction type prefix\n    if data[0] < 0x80 {\n        data = &data[1..];\n    }\n\n    let list_header =\n        alloy_rlp::Header::decode(&mut data).map_err(|e| anyhow!(\"invalid receipt RLP: {e}\"))?;\n    ensure!(list_header.list, \"receipt must be an RLP list\");\n\n    // Limit reads to the receipt's declared payload.\n    ensure!(\n        data.len() >= list_header.payload_length,\n        \"receipt payload extends past available data\"\n    );\n    let mut data = &data[..list_header.payload_length];\n\n    // Skip: status (0), cumulative_gas_used (1), logs_bloom (2)\n    for i in 0..3 {\n        skip_rlp_item(&mut data).map_err(|e| anyhow!(\"failed to skip receipt field {i}: {e}\"))?;\n    }\n\n    // Decode the logs list\n    let logs_header =\n        alloy_rlp::Header::decode(&mut data).map_err(|e| anyhow!(\"invalid logs list RLP: {e}\"))?;\n    ensure!(logs_header.list, \"logs must be an RLP list\");\n    ensure!(\n        data.len() >= logs_header.payload_length,\n        \"logs payload extends past receipt boundary\"\n    );","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-bridge/src/proof/mod.rs#L371-L407","documentation":"decode_receipt_logs bounds-checks the receipt's declared payload_length against the bytes remaining after the RLP header. If the length prefix claims more data than is present, the ensure! fails before any slicing, preventing an out-of-bounds panic at `&data[..payload_length]` and rejecting malformed/truncated receipts.","triggerScenarios":"Truncated receipt bytes (partial RPC response, message framing bug); adversarial input with an inflated RLP length field; upstream code slicing the receipt short after stripping a prefix it shouldn't have.","commonSituations":"Fixed 512/1024-byte buffers truncating large receipts with many logs; a relayer relaying only the first N bytes; test fixtures copied from logs with ellipsis.","solutions":["Log remaining length vs payload_length to confirm truncation, then fix the producer/transport layer","Fetch receipts from a trusted node and pass bytes verbatim","Ensure buffers carrying receipts are dynamically sized (Vec<u8>) not fixed arrays"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match decode_receipt_logs(receipt_rlp) {\n    Ok(logs) => logs,\n    Err(e) if e.to_string().contains(\"extends past available data\") => {\n        // truncated input: refetch, never retry the same bytes\n        anyhow::bail!(\"truncated receipt RLP ({} bytes); refetch from RPC\", receipt_rlp.len())\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Carry receipt bytes in dynamically sized buffers; avoid fixed-size truncating arrays","Log declared payload_length vs actual length when catches occur to locate the truncating layer","Verify end-to-end integrity (checksums or length framing) for relayed proof payloads"],"tags":["ethereum","rlp","receipt","truncated-data","bridge","rust"],"backgroundTag":"rlp-decoding-failed","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}