{"record":{"id":"cb3c1a9ebb9c2640","repo":"Pumpkin-MC/Pumpkin","slug":"slots-len-exceeds-limit","errorCode":null,"errorMessage":"slots_len exceeds limit","messagePattern":"slots_len exceeds limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pumpkin-protocol/src/bedrock/server/player_auth_input.rs","lineNumber":166,"sourceCode":"    }\n}\n\n#[derive(Debug)]\npub struct PlayerInventoryAction {\n    pub legacy_request_id: VarInt,\n    pub legacy_slots: Vec<crate::bedrock::server::inventory_transaction::LegacySetItemSlot>,\n    pub actions: Vec<crate::bedrock::server::inventory_transaction::InventoryAction>,\n    pub transaction: PlayerUseItemTransactionData,\n}\n\nimpl PacketRead for PlayerInventoryAction {\n    fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {\n        let legacy_request_id = VarInt::read(buf)?;\n        let mut legacy_slots = Vec::new();\n        if bool::read(buf)? && legacy_request_id.0 < -1 && (legacy_request_id.0 & 1) == 0 {\n            let slots_len = VarUInt::read(buf)?.0 as usize;\n            if slots_len > 1024 {\n                return Err(Error::new(\n                    ErrorKind::InvalidData,\n                    \"slots_len exceeds limit\",\n                ));\n            }\n            legacy_slots.reserve(slots_len.min(64));\n            for _ in 0..slots_len {\n                legacy_slots.push(\n                    crate::bedrock::server::inventory_transaction::LegacySetItemSlot::read(buf)?,\n                );\n            }\n        }\n        let mut actions = Vec::new();\n        if bool::read(buf)? && bool::read(buf)? {\n            let actions_len = VarUInt::read(buf)?.0 as usize;\n            if actions_len > 1024 {\n                return Err(Error::new(\n                    ErrorKind::InvalidData,\n                    \"actions_len exceeds limit\",","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-protocol/src/bedrock/server/player_auth_input.rs#L148-L184","documentation":"Thrown while decoding legacy inventory slots in the Bedrock PlayerAuthInput packet when the declared slots length exceeds 1024. The limit stops untrusted input from forcing huge allocations or long parse loops.","triggerScenarios":"PlayerAuthInput with a legacy request id that is < -1 and even, where the subsequent VarUInt slots_len is > 1024.","commonSituations":"Exploit attempts with inflated length prefixes, protocol version mismatches, or corrupted packet streams.","solutions":["Verify client and server Bedrock protocol versions align","Check network path for corruption/desync","Treat repeat offenders as malicious and disconnect them","Only raise the 1024 limit if a legitimate use case exists"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let slots_len = VarUInt::read(buf)?.0 as usize;\nif slots_len > 1024 { return Err(...); }","typeGuard":null,"tryCatchPattern":"if let Err(e) = packet.read(&mut reader) {\n    if e.kind() == std::io::ErrorKind::InvalidData { return disconnect(peer); }\n    return Err(e.into());\n}","preventionTips":["Validate every length prefix against a protocol constant","Reserve only min(len, cap) capacity","Test decoders with hostile length values (usize::MAX encoded)","Keep protocol version negotiation strict"],"tags":["bedrock","protocol","packet-decoding","length-validation"],"backgroundTag":"value-out-of-range","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}