From 0d06fff983496fb3c453e7318d3fd722ca6201cf Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Sep 2026 07:45:48 +0000 Subject: [PATCH] fix(security): confirmIDs returns the integers it checked InputValidator::confirmIDs() kept an id when intval($id) > 0 but returned the original value, and its callers implode the result into SQL `IN (...)` lists (mass edit and delete of lines, users, streams, series; bouquet contents; global search). '1) OR (1=1' has an intval of 1, so it passed the filter and reached the query unchanged. It now returns the integers. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01V2uBUbGApb4A7Rbcoi7dxA --- src/Core/Validation/InputValidator.php | 6 ++++-- tests/Unit/InputValidatorTest.php | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Core/Validation/InputValidator.php b/src/Core/Validation/InputValidator.php index 203715a5..33bbc94d 100644 --- a/src/Core/Validation/InputValidator.php +++ b/src/Core/Validation/InputValidator.php @@ -180,13 +180,15 @@ class InputValidator { * Filter array to only positive integer IDs * * @param array $ids Input array of IDs - * @return array Filtered array with only positive integer IDs + * @return int[] The positive integer IDs. Callers implode these into SQL + * `IN (...)` lists, so the integer is returned, never the input + * string (`'1) OR (1=1'` passes an intval() > 0 test). */ public static function confirmIDs(array $ids) { $result = []; foreach ($ids as $id) { if (intval($id) > 0) { - $result[] = $id; + $result[] = intval($id); } } return $result; diff --git a/tests/Unit/InputValidatorTest.php b/tests/Unit/InputValidatorTest.php index fb01220e..fe8bc68b 100644 --- a/tests/Unit/InputValidatorTest.php +++ b/tests/Unit/InputValidatorTest.php @@ -28,4 +28,14 @@ final class InputValidatorTest extends TestCase { $result = InputValidator::validateOrFail('processProvider', array('ip' => '127.0.0.1')); $this->assertSame(STATUS_INVALID_INPUT, $result['status']); } + + /** + * Callers implode the result straight into `IN (...)`, so what comes back + * must be the integers, not the strings that merely start with one. + */ + public function testConfirmIdsReturnsIntegers() { + $this->assertSame([5, 12], InputValidator::confirmIDs(['5', '0', '-3', 'abc', '12'])); + $this->assertSame([1], InputValidator::confirmIDs(['1) OR (1=1'])); + $this->assertSame([7], InputValidator::confirmIDs([7])); + } }