RUSTSEC-2026-0498: BEEF validation answers valid for a raw entry that is not a transaction
Beef::mergerawtx and BeefTx::fromrawtx accept raw bytes without a Result. For bytes that are not exactly one transaction (a transaction followed by bytes, a cut transaction, bytes that are no transaction at all), Beef::sorttxs, verifystructure, verifyvalid and isvalid could answer valid, even with no BUMP and no parent in the BEEF, and, where the entry carried a BUMP index, treat the hash of those bytes as a proven transaction id; an entry that names it as a parent was answered valid too.
The wire readers (Beef::frombinary, verifystream, Transaction::frombeef, fromatomicbeef) parse every entry and are not affected. Reaching this needs an application that passes bytes it did not parse to mergerawtx or BeefTx::fromrawtx and then relies on the verdict or on the transaction the BEEF hands back.
0.8.5 refuses such an entry at all four verdict doors, with or without a BUMP index, and every entry that names it as a parent. Where upgrading is not possible, do not rely on isvalid or verifyvalid alone for such an entry: check that the bytes are exactly one transaction before merging them.
Other sources
Transaction::frombinary and Transaction::fromhex read one transaction from the front of their input, did not check that the input ended there, and kept the whole input as the transaction's cached serialization: tobinary, tohex and id() then answered for bytes that are not the transaction's. Transaction::fromjson, given a hex field, reads it through fromhex and answers the same. fromef, fromhexef and parsescriptoffsets also read a prefix.
An application that takes bytes or hex from outside, parses them with these readers and then uses id() or the serialization could be given one transaction under another identity: the same parsed fields, a different id. An application that passes them only bytes it produced or has already checked is not affected.
0.8.5 refuses a byte after the transaction; Transaction::fromreader reads from the front of a longer buffer. Where upgrading is not possible, parse with Transaction::frombinary, call tx.invalidatecaches() (public from 0.3.16) and require tx.tobinary() == bytes.
— OSV
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
rust/bsv-rsto a version that resolves this vulnerability.Fixed in 0.8.5 - Upgrade
Upgrade
rust/bsv-rsto a version that resolves this vulnerability.Fixed in 0.9.0-beta.7.0 - Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Fixed in 0.8.5 - Compensating control
For externally supplied bytes or hex, require the input to be exactly one complete transaction before merging or accepting it; verify that parsing consumed the entire input and that tx.to_binary() == bytes. Do not rely on is_valid or verify_valid alone for raw entries.
- Operational
After calling Transaction::from_binary, call tx.invalidate_caches() before using cached serialization or id().
Event History
Frequently Asked Questions
Which applications are exposed to this issue?
Exposure requires an application to pass raw transaction bytes that it did not parse into Beef::merge_raw_tx or BeefTx::from_raw_tx, then rely on a BEEF validity verdict or on the transaction returned by the BEEF. The wire-reader paths Beef::from_binary, verify_stream, Transaction::from_beef, and from_atomic_beef parse every entry and are not affected.
What malformed input can be accepted as valid?
Affected paths can report valid for bytes that are not exactly one transaction, including a transaction followed by extra bytes, a truncated transaction, or bytes that are not a transaction. This can also affect entries with a BUMP index and entries that name the malformed entry as a parent.
How can this be mitigated before upgrading?
Before passing raw bytes to Beef::merge_raw_tx or BeefTx::from_raw_tx, verify that they represent exactly one transaction. Do not rely on is_valid or verify_valid alone for entries created from unparsed raw bytes.
What version changes the affected validation behavior?
Version 0.8.5 refuses these malformed entries at all four verdict paths, regardless of whether they carry a BUMP index, and also rejects entries that name them as parents.