From a38facd561a1fa9e25840272699e75f68b9a754e Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Mon, 19 Jan 2026 02:55:58 +0100 Subject: [PATCH] Remove DeclaredHandler to prevent accidental internal discovery The `DeclaredHandler` has become a liability. Because class, interface, and enum names are represented as strings, we run the risk of the library "helpfully" identifying a piece of user input as an internal system part. If a user happens to input a string that matches an internal class or enum name, the stringifier would automatically confirm its existence by applying the specialized formatting. This creates an information leakage vulnerability where an outsider could map out our application's internal architecture simply by guessing names. By removing this handler, we ensure that a string is treated just as a string. This follows our recent "secure-by-default" trend seen in the `CallableStringifier` changes: we are prioritizing the privacy of the application's internal blueprint over the convenience of automatic type detection. --- README.md | 9 --- src/Handlers/CompositeHandler.php | 1 - src/Handlers/DeclaredHandler.php | 42 -------------- tests/integration/stringify-declared.phpt | 21 ------- tests/unit/Handlers/DeclaredHandlerTest.php | 61 --------------------- 5 files changed, 134 deletions(-) delete mode 100644 src/Handlers/DeclaredHandler.php delete mode 100644 tests/integration/stringify-declared.phpt delete mode 100644 tests/unit/Handlers/DeclaredHandlerTest.php diff --git a/README.md b/README.md index 10819b6..01c8222 100644 --- a/README.md +++ b/README.md @@ -83,12 +83,6 @@ echo stringify(['foo' => true, 'bar' => 42, 'baz' => ['qux' => INF, 'quux' => nu echo stringify(tmpfile()) . PHP_EOL; // `resource ` -echo stringify(BasicEnumeration::FOO) . PHP_EOL; -// `BasicEnumeration::FOO` - -echo stringify(BackedEnumeration::QUX) . PHP_EOL; -// `BackedEnumeration::QUX` - echo stringify(new WithProperties()) . PHP_EOL; // `WithProperties { +$publicProperty=true #$protectedProperty=42 -$privateProperty="something" }` @@ -136,9 +130,6 @@ echo stringify(new RuntimeException()) . PHP_EOL; echo stringify(new InvalidArgumentException('This is the exception message')) . PHP_EOL; // `InvalidArgumentException { "This is the exception message" in file.php:112 }` - -echo stringify(Traversable::class) . PHP_EOL; -// `Traversable` ``` To see more examples of how to use the library check the [integration tests](tests/integration). diff --git a/src/Handlers/CompositeHandler.php b/src/Handlers/CompositeHandler.php index f0ef261..6b7f21e 100644 --- a/src/Handlers/CompositeHandler.php +++ b/src/Handlers/CompositeHandler.php @@ -41,7 +41,6 @@ public static function create(): self new ResourceHandler($quoter), new BoolHandler($quoter), new NullHandler($quoter), - new DeclaredHandler($quoter), $jsonEncodableHandler = new JsonEncodableHandler(), ); $handler->prependHandler( diff --git a/src/Handlers/DeclaredHandler.php b/src/Handlers/DeclaredHandler.php deleted file mode 100644 index d88720d..0000000 --- a/src/Handlers/DeclaredHandler.php +++ /dev/null @@ -1,42 +0,0 @@ - - * SPDX-License-Identifier: MIT - */ - -declare(strict_types=1); - -namespace Respect\Stringifier\Handlers; - -use Respect\Stringifier\Handler; -use Respect\Stringifier\Quoter; - -use function class_exists; -use function enum_exists; -use function interface_exists; -use function is_string; -use function trait_exists; - -final class DeclaredHandler implements Handler -{ - public function __construct( - private readonly Quoter $quoter, - ) { - } - - public function handle(mixed $raw, int $depth): string|null - { - if (!is_string($raw) || $this->isNotDeclared($raw)) { - return null; - } - - return $this->quoter->quote($raw, $depth); - } - - public function isNotDeclared(string $raw): bool - { - return !class_exists($raw) && !interface_exists($raw) && !trait_exists($raw) && !enum_exists($raw); - } -} diff --git a/tests/integration/stringify-declared.phpt b/tests/integration/stringify-declared.phpt deleted file mode 100644 index ce511ce..0000000 --- a/tests/integration/stringify-declared.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---FILE-- - ---EXPECT-- -`Traversable` -`ArrayIterator` -`BasicEnumeration` -`Respect\Stringifier\Helpers\ObjectHelper` diff --git a/tests/unit/Handlers/DeclaredHandlerTest.php b/tests/unit/Handlers/DeclaredHandlerTest.php deleted file mode 100644 index d39f24e..0000000 --- a/tests/unit/Handlers/DeclaredHandlerTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - * SPDX-License-Identifier: MIT - */ - -declare(strict_types=1); - -namespace Respect\Stringifier\Test\Unit\Handlers; - -use ArrayObject; -use BasicEnumeration; -use Countable; -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; -use Respect\Stringifier\Handlers\DeclaredHandler; -use Respect\Stringifier\Helpers\ObjectHelper; -use Respect\Stringifier\Test\Double\FakeQuoter; - -#[CoversClass(DeclaredHandler::class)] -final class DeclaredHandlerTest extends TestCase -{ - private const int DEPTH = 0; - - #[Test] - public function itShouldNotStringifyWhenRawValueIsNotExists(): void - { - $sut = new DeclaredHandler(new FakeQuoter()); - - self::assertNull($sut->handle('NotAClassInterfaceTraitOrEnum', self::DEPTH)); - } - - #[Test] - #[DataProvider('existsRawValuesProvider')] - public function itShouldStringifyWhenRawValueIsExists(string $raw): void - { - $quoter = new FakeQuoter(); - - $sut = new DeclaredHandler($quoter); - - $actual = $sut->handle($raw, self::DEPTH); - $expected = $quoter->quote($raw, self::DEPTH); - - self::assertEquals($expected, $actual); - } - - /** @return array> */ - public static function existsRawValuesProvider(): array - { - return [ - [ArrayObject::class], - [Countable::class], - [BasicEnumeration::class], - [ObjectHelper::class], - ]; - } -}