From bab841b18d52b80387e043cd9e0fe91ed4b5e7f1 Mon Sep 17 00:00:00 2001 From: Acts1631 Date: Wed, 16 Sep 2026 19:43:30 -0400 Subject: [PATCH 1/2] Reject client race-finished notifications --- src/network/protocols/game_events_protocol.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index 2ba6d3485b4..68811b545d9 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -66,6 +66,13 @@ bool GameEventsProtocol::notifyEvent(Event* event) switch (type) { case GE_KART_FINISHED_RACE: + if (NetworkConfig::get()->isServer()) + { + Log::warn("GameEventsProtocol", + "Ignoring client race-finished notification from %s.", + event->getPeer()->getAddress().toString().c_str()); + break; + } kartFinishedRace(data); break; case GE_RESET_BALL: { From 1bc2e65c1e3f5e12985aef0f1457eb0949f2a463 Mon Sep 17 00:00:00 2001 From: Acts1631 Date: Mon, 21 Sep 2026 16:37:33 -0400 Subject: [PATCH 2/2] Restrict game events accepted from clients Only startup boost requests are sent from clients. Reject other\ngame-event types before they can modify server-side game state, and\nvalidate the startup-boost payload length. --- .../protocols/game_events_protocol.cpp | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index 68811b545d9..148aa980bbc 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -59,6 +59,15 @@ bool GameEventsProtocol::notifyEvent(Event* event) return true; } uint8_t type = data.getUInt8(); + // Only startup boost is sent from a client. All other game events are + // notifications sent by the server. + if (NetworkConfig::get()->isServer() && type != GE_STARTUP_BOOST) + { + Log::warn("GameEventsProtocol", + "Ignoring client game event %d from %s.", type, + event->getPeer()->getAddress().toString().c_str()); + return true; + } CaptureTheFlag* ctf = dynamic_cast(World::getWorld()); FreeForAll* ffa = dynamic_cast(World::getWorld()); SoccerWorld* sw = dynamic_cast(World::getWorld()); @@ -66,13 +75,6 @@ bool GameEventsProtocol::notifyEvent(Event* event) switch (type) { case GE_KART_FINISHED_RACE: - if (NetworkConfig::get()->isServer()) - { - Log::warn("GameEventsProtocol", - "Ignoring client race-finished notification from %s.", - event->getPeer()->getAddress().toString().c_str()); - break; - } kartFinishedRace(data); break; case GE_RESET_BALL: { @@ -112,6 +114,12 @@ bool GameEventsProtocol::notifyEvent(Event* event) { if (NetworkConfig::get()->isServer()) { + if (data.size() < 1) + { + Log::warn("GameEventsProtocol", + "Too short startup boost request."); + return true; + } uint8_t kart_id = data.getUInt8(); if (!event->getPeer()->availableKartID(kart_id)) {