From e46430034644aca77992a31305a7272b1ca5d9e8 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 11 Mar 2026 14:13:09 -0700 Subject: [PATCH] Add pointCount cap to SMSG_MONSTER_MOVE spline parsing Improve robustness of monster move spline parsing by capping the pointCount field to prevent excessive iteration from malformed or malicious packets. - WotLK: Cap pointCount to 1000 waypoints (realistic maximum for movement) - Vanilla (Turtle): Reduce existing cap from 16384 to 1000 and add warning logging when cap is applied - Both variants now log warnings when cap is exceeded, including guid context A malicious or corrupted server sending an unrealistic pointCount value (e.g. uint32_max) could previously cause the client to allocate excessive memory or iterate excessively. The 1000-waypoint cap aligns with realistic movement paths while protecting against DoS vectors. Part of ongoing Tier 2 work to improve multi-expansion packet parsing robustness. --- src/game/world_packets.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index ba6742fc..b8939356 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -2723,6 +2723,14 @@ bool MonsterMoveParser::parse(network::Packet& packet, MonsterMoveData& data) { if (pointCount == 0) return true; + // Cap pointCount to prevent excessive iteration from malformed packets + constexpr uint32_t kMaxSplinePoints = 1000; + if (pointCount > kMaxSplinePoints) { + LOG_WARNING("SMSG_MONSTER_MOVE: pointCount=", pointCount, " exceeds max ", kMaxSplinePoints, + " (guid=0x", std::hex, data.guid, std::dec, "), capping"); + pointCount = kMaxSplinePoints; + } + // Catmullrom or Flying → all waypoints stored as absolute float3 (uncompressed). // Otherwise: first float3 is final destination, remaining are packed deltas. bool uncompressed = (data.splineFlags & (0x00080000 | 0x00002000)) != 0; @@ -2824,7 +2832,14 @@ bool MonsterMoveParser::parseVanilla(network::Packet& packet, MonsterMoveData& d uint32_t pointCount = packet.readUInt32(); if (pointCount == 0) return true; - if (pointCount > 16384) return false; // sanity + + // Cap pointCount to prevent excessive iteration from malformed packets + constexpr uint32_t kMaxSplinePoints = 1000; + if (pointCount > kMaxSplinePoints) { + LOG_WARNING("SMSG_MONSTER_MOVE(Vanilla): pointCount=", pointCount, " exceeds max ", kMaxSplinePoints, + " (guid=0x", std::hex, data.guid, std::dec, "), capping"); + pointCount = kMaxSplinePoints; + } // First float[3] is destination. if (packet.getReadPos() + 12 > packet.getSize()) return true;