From d1b66bdbd64563df2b135fe968b40b0793a6f701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Sat, 11 Apr 2026 19:20:07 +0200 Subject: [PATCH 1/2] Use cryptographically secure random bytes in RandomStringTrait str_shuffle() relies on mt_rand which is not cryptographically secure. Replace with random_bytes() so placeholder passwords for social-login users cannot be predicted. Output changes from alphanumeric [a-zA-Z0-9] to hex [0-9a-f]. --- src/Traits/RandomStringTrait.php | 4 +--- .../TestCase/Traits/RandomStringTraitTest.php | 23 +++++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Traits/RandomStringTrait.php b/src/Traits/RandomStringTrait.php index 3b5db6d1..1fc5a3eb 100644 --- a/src/Traits/RandomStringTrait.php +++ b/src/Traits/RandomStringTrait.php @@ -26,8 +26,6 @@ public function randomString($length = 10) if (!is_numeric($length) || $length <= 0) { $length = 10; } - $string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - - return substr(str_shuffle($string), 0, $length); + return substr(bin2hex(random_bytes((int)ceil($length / 2))), 0, $length); } } diff --git a/tests/TestCase/Traits/RandomStringTraitTest.php b/tests/TestCase/Traits/RandomStringTraitTest.php index 46641b62..0fa5d5e8 100644 --- a/tests/TestCase/Traits/RandomStringTraitTest.php +++ b/tests/TestCase/Traits/RandomStringTraitTest.php @@ -33,18 +33,21 @@ public function tearDown(): void parent::tearDown(); } - public function testRandomString() + public function testRandomStringLength() { - $result = $this->Trait->randomString(); - $this->assertEquals(10, strlen($result)); - - $result = $this->Trait->randomString(30); - $this->assertEquals(30, strlen($result)); + $this->assertSame(10, strlen($this->Trait->randomString())); + $this->assertSame(30, strlen($this->Trait->randomString(30))); + $this->assertSame(10, strlen($this->Trait->randomString('-300'))); + $this->assertSame(10, strlen($this->Trait->randomString('text'))); + } - $result = $this->Trait->randomString('-300'); - $this->assertEquals(10, strlen($result)); + public function testRandomStringUsesSecureRandomness() + { + $first = $this->Trait->randomString(32); + $second = $this->Trait->randomString(32); - $result = $this->Trait->randomString('text'); - $this->assertEquals(10, strlen($result)); + $this->assertNotSame($first, $second); + $this->assertMatchesRegularExpression('/^[0-9a-f]+$/', $first); + $this->assertMatchesRegularExpression('/^[0-9a-f]+$/', $second); } } From 1401b4b66818fc635a297399773addda164640b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Sat, 11 Apr 2026 19:38:29 +0200 Subject: [PATCH 2/2] Preserve alphanumeric entropy in RandomStringTrait using random_int Replace bin2hex(random_bytes()) with random_int() over the full 62-char alphabet to maintain ~59 bits of entropy at default length (vs ~40 bits with hex output). Cast $length to int after validation and add odd-length and length-assertion tests. --- src/Traits/RandomStringTrait.php | 10 +++++++++- tests/TestCase/Traits/RandomStringTraitTest.php | 12 ++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Traits/RandomStringTrait.php b/src/Traits/RandomStringTrait.php index 1fc5a3eb..4a351cef 100644 --- a/src/Traits/RandomStringTrait.php +++ b/src/Traits/RandomStringTrait.php @@ -26,6 +26,14 @@ public function randomString($length = 10) if (!is_numeric($length) || $length <= 0) { $length = 10; } - return substr(bin2hex(random_bytes((int)ceil($length / 2))), 0, $length); + $length = (int)$length; + $alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $alphabetLength = strlen($alphabet); + $result = ''; + for ($i = 0; $i < $length; $i++) { + $result .= $alphabet[random_int(0, $alphabetLength - 1)]; + } + + return $result; } } diff --git a/tests/TestCase/Traits/RandomStringTraitTest.php b/tests/TestCase/Traits/RandomStringTraitTest.php index 0fa5d5e8..a62a8a6c 100644 --- a/tests/TestCase/Traits/RandomStringTraitTest.php +++ b/tests/TestCase/Traits/RandomStringTraitTest.php @@ -46,8 +46,16 @@ public function testRandomStringUsesSecureRandomness() $first = $this->Trait->randomString(32); $second = $this->Trait->randomString(32); + $this->assertSame(32, strlen($first)); + $this->assertSame(32, strlen($second)); $this->assertNotSame($first, $second); - $this->assertMatchesRegularExpression('/^[0-9a-f]+$/', $first); - $this->assertMatchesRegularExpression('/^[0-9a-f]+$/', $second); + $this->assertMatchesRegularExpression('/^[0-9a-zA-Z]+$/', $first); + $this->assertMatchesRegularExpression('/^[0-9a-zA-Z]+$/', $second); + } + + public function testRandomStringOddLength() + { + $this->assertSame(31, strlen($this->Trait->randomString(31))); + $this->assertSame(1, strlen($this->Trait->randomString(1))); } }