From 5c1558788a57b768d0bd9ee3c5fde2e728318c72 Mon Sep 17 00:00:00 2001 From: dongzh1 <43366518+dongzh1@users.noreply.github.com> Date: Sun, 12 Jul 2026 00:34:24 +0800 Subject: [PATCH] fix(net): avoid panics on malformed encryption/velocity login responses (#2310) `handle_encryption_response` unwrapped the RSA decrypt of the client-supplied shared secret, panicking the connection task on a malformed value; kick the client instead, mirroring the adjacent `set_encryption` error handling. `receive_velocity_plugin_response` called `data.split_at(32)` without a length check, panicking on a velocity response shorter than 32 bytes; guard the length and return `FailedVerifyIntegrity`. Co-authored-by: Claude Opus 4.8 (1M context) --- pumpkin/src/net/java/login.rs | 9 +++++---- pumpkin/src/net/proxy/velocity.rs | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pumpkin/src/net/java/login.rs b/pumpkin/src/net/java/login.rs index 883018b36..3546105cb 100644 --- a/pumpkin/src/net/java/login.rs +++ b/pumpkin/src/net/java/login.rs @@ -114,10 +114,11 @@ impl JavaClient { encryption_response: SEncryptionResponse, ) { debug!("Handling encryption"); - let shared_secret = server - .decrypt(&encryption_response.shared_secret) - .await - .unwrap(); + let Ok(shared_secret) = server.decrypt(&encryption_response.shared_secret).await else { + self.kick(TextComponent::text("Failed to decrypt shared secret")) + .await; + return; + }; if let Err(error) = self.set_encryption(&shared_secret).await { self.kick(TextComponent::text(error.to_string())).await; diff --git a/pumpkin/src/net/proxy/velocity.rs b/pumpkin/src/net/proxy/velocity.rs index 6563dec21..2325e7bae 100644 --- a/pumpkin/src/net/proxy/velocity.rs +++ b/pumpkin/src/net/proxy/velocity.rs @@ -112,6 +112,9 @@ pub fn receive_velocity_plugin_response( ) -> Result<(GameProfile, SocketAddr), VelocityError> { debug!("Received velocity response"); if let Some(data) = response.data { + if data.len() < 32 { + return Err(VelocityError::FailedVerifyIntegrity); + } let (signature, mut data_without_signature) = data.split_at(32); if !check_integrity((signature, data_without_signature), &config.secret) {