From b03a727eae43f1790b0d7c6fe10fed68533dfc0f Mon Sep 17 00:00:00 2001 From: Konseptt <49203341+Konseptt@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:22:27 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20ECS=20logic=20bug=20causing=20Application=20DoS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replaced `return` with `continue` in `car_nn_controlled_system` query iterator loop to prevent single entity failure from halting execution for all subsequent entities. - Replaced direct array indexing on neural network outputs with `.get().copied().unwrap_or(0.0)` for safe fallbacks, avoiding potential out-of-bounds panics. - Documented findings in `.jules/sentinel.md` as per Sentinel operating procedure. --- .jules/sentinel.md | 4 ++++ src/car.rs | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..e378027 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-06-25 - [Logic Bug DoS via Return Statement] +**Vulnerability:** A `return;` statement within the ECS system `car_nn_controlled_system`'s query iteration loop halted the entire system for all entities as soon as one car had an empty `ray_inputs` array. +**Learning:** In Bevy (and other ECS frameworks), using `return` inside a `Query::iter_mut()` loop exits the system function completely. This causes a single entity's invalid state to inflict a Denial of Service on all other entities processed by that system. +**Prevention:** Use `continue;` to safely skip the current iteration/entity and proceed to process the remaining entities. Always ensure loops handling multiple entities do not break/return prematurely due to one entity's missing state. \ No newline at end of file diff --git a/src/car.rs b/src/car.rs index 182b6a9..e17572d 100644 --- a/src/car.rs +++ b/src/car.rs @@ -140,19 +140,19 @@ fn car_nn_controlled_system( if brain.ray_inputs.is_empty() { speed.0 = 0.0; turn_speed.0 = 0.0; - return; + continue; } brain.nn_outputs = brain.nn.predict(&brain.ray_inputs); let nn_out = brain.nn_outputs.last().unwrap().clone(); // nn_out = brain.nn.predict(&brain.ray_inputs).pop().unwrap(); - let w_key = nn_out[0] >= NN_W_ACTIVATION_THRESHOLD; - let s_key = nn_out[2] >= NN_S_ACTIVATION_THRESHOLD; + let w_key = nn_out.get(0).copied().unwrap_or(0.0) >= NN_W_ACTIVATION_THRESHOLD; + let s_key = nn_out.get(2).copied().unwrap_or(0.0) >= NN_S_ACTIVATION_THRESHOLD; let mut a_key = false; let mut d_key = false; - if nn_out[1] >= 0.5 { + if nn_out.get(1).copied().unwrap_or(0.0) >= 0.5 { a_key = true; } else { d_key = true;