From ae1813735b4d8d67aa07eb5586b88e0f3f5bee1a Mon Sep 17 00:00:00 2001 From: dongzh1 <43366518+dongzh1@users.noreply.github.com> Date: Wed, 1 Jul 2026 19:43:54 +0800 Subject: [PATCH] fix(inventory): guard Swap slot click against negative slot index (#2313) The `Swap` branch of `internal_on_slot_click` indexed `self.get_behaviour().slots[slot_index as usize]` without first checking `slot_index >= 0`, unlike every sibling branch (Pickup, QuickMove, Throw, Clone, QuickCraft) which all guard with `if slot_index < 0 { return; }`. `slot_index` originates from the client `SClickSlot` packet (`i16` slot field, widened to `i32`). The upstream validation in `Player::on_slot_click` relies on `ScreenHandler::is_slot_valid`, whose check `slot == -1 || slot == -999 || slot < slots.len() as i32` returns `true` for ANY negative slot (a negative value is always `< slots.len()`), so negative indices are not filtered out before reaching the handler. A crafted Swap packet with a negative slot (e.g. -5) and a hotbar button in `0..9` (or 40) therefore evaluated `slots[(-5) as usize]`, an enormous index, causing an out-of-bounds Vec panic and crashing the server. Add the same `if slot_index < 0 { return; }` guard at the top of the Swap branch, matching the sibling branches exactly. Minimal, low-risk: legitimate Swap clicks always carry a non-negative container slot, so behaviour is unchanged for valid input. --- pumpkin-inventory/src/screen_handler.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pumpkin-inventory/src/screen_handler.rs b/pumpkin-inventory/src/screen_handler.rs index 4e8b1a165..5e76f3594 100644 --- a/pumpkin-inventory/src/screen_handler.rs +++ b/pumpkin-inventory/src/screen_handler.rs @@ -1223,6 +1223,9 @@ pub trait ScreenHandler: Send + Sync { } else if action_type == SlotActionType::Swap && (0..9).contains(&button) || button == 40 { + if slot_index < 0 { + return; + } let mut button_stack = player .get_inventory() .get_stack(button as usize)