From efc394ce9ef976da1cdc34e011273453038ea088 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 11 Mar 2026 14:33:02 -0700 Subject: [PATCH] Cap spell cooldown entries in SpellCooldownParser SMSG_SPELL_COOLDOWN (3.3.5a) improvements: - Validate 9-byte minimum for guid + flags - Cap cooldown entries to 512 (each entry is 8 bytes: spellId + ms) - Prevent unbounded memory allocation from malformed packets - Log warning when cap is reached with remaining data ignored Prevents DoS from servers sending malformed cooldown lists. --- src/game/world_packets.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index 9a9c091e..4332e1c4 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -3437,13 +3437,25 @@ bool AuraUpdateParser::parse(network::Packet& packet, AuraUpdateData& data, bool } bool SpellCooldownParser::parse(network::Packet& packet, SpellCooldownData& data) { + // Upfront validation: guid(8) + flags(1) = 9 bytes minimum + if (packet.getSize() - packet.getReadPos() < 9) return false; + data.guid = packet.readUInt64(); data.flags = packet.readUInt8(); - while (packet.getReadPos() + 8 <= packet.getSize()) { + // Cap cooldown entries to prevent unbounded memory allocation (each entry is 8 bytes) + uint32_t maxCooldowns = 512; + uint32_t cooldownCount = 0; + + while (packet.getReadPos() + 8 <= packet.getSize() && cooldownCount < maxCooldowns) { uint32_t spellId = packet.readUInt32(); uint32_t cooldownMs = packet.readUInt32(); data.cooldowns.push_back({spellId, cooldownMs}); + cooldownCount++; + } + + if (cooldownCount >= maxCooldowns && packet.getReadPos() + 8 <= packet.getSize()) { + LOG_WARNING("Spell cooldowns: capped at ", maxCooldowns, " entries, remaining data ignored"); } LOG_DEBUG("Spell cooldowns: ", data.cooldowns.size(), " entries");