Correct deserialization of `u16::MAX` byte-Features
What changed, and why it matters
This commit fixes a mismatch in how Lightning feature flags are read from the wire. Previously, a feature set whose serialized byte length was exactly 65,535 bytes (u16::MAX) could be deserialized incorrectly because the code used a generic vector reader that may interpret the length differently. The fix reads the length as a u16 and then reads exactly that many bytes, matching the write side. The commit message says this 'shouldn't really matter in practice.'
Review whether the old `Vec::<u8>::read` behavior for `u16::MAX` could cause panics, truncated reads, or protocol confusion in production. Consider adding regression tests for `u16::MAX`-sized feature vectors. No immediate emergency action is indicated by the commit message, but the fix should be included in the next release.
Security signals we found
Deserialization length mismatch between read and write paths
Potential incorrect parsing of maximally-sized length-prefixed feature vectors
Reported by external party (Project Loupe)
Evidence from the diff
The patch changes the Readable implementation generated by impl_feature_len_prefixed_write! in lightning/src/ln/features.rs. Before, it called Vec::<u8>::read(r), which in this codebase reads a length prefix as a u16 but may apply special handling for the max value (e.g., treating u16::MAX as a sentinel or using a different encoding). After, it explicitly reads a u16 length, allocates a buffer of that size, and calls read_exact. This aligns deserialization with the corresponding Writeable implementation, which writes a u16 length prefix followed by the bytes. The issue was reported by Project Loupe.
Changed components
lightning/src/ln/features.rsimpl_feature_len_prefixed_write macroLightning feature flag serialization/deserializationInspect captured patch +4 / −1
diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs
index a4e7fc1..a303027 100644
--- a/lightning/src/ln/features.rs
+++ b/lightning/src/ln/features.rs
@@ -40,7 +40,10 @@ macro_rules! impl_feature_len_prefixed_write {
}
impl Readable for $features {
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
- Ok(Self::from_be_bytes(Vec::<u8>::read(r)?))
+ let len: u16 = Readable::read(r)?;
+ let mut bytes = vec![0u8; len as usize];
+ r.read_exact(&mut bytes[..])?;
+ Ok(Self::from_be_bytes(bytes))
}
}
};
Why this scored 38/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.