Performance and precision pass (#64)

This commit is contained in:
Eli Peter 2026-05-04 19:58:04 -04:00 committed by GitHub
parent c7c5e0f3a1
commit fb698d2c27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
97 changed files with 9932 additions and 517 deletions

View file

@ -0,0 +1,25 @@
<?php
// Vulnerable counterpart to safe_serializable_magic_method_unserialize.php.
// The enclosing method is named `unserialize` but the call argument is NOT
// the formal parameter — the developer is passing user input directly to
// PHP's `\unserialize()`. The Serializable magic-method recogniser is
// designed to refuse this shape (the call's argument must be a bare
// reference to the method's single formal parameter). Must still fire
// `php.deser.unserialize`.
class Mishandled {
public function unserialize($input): void {
// BUG: ignores $input, reads from superglobal.
$this->payload = unserialize($_GET['blob']);
}
}
class WrappedThenUnserialize {
// Wrapped argument inside magic method — conservative: still fires.
// Real-world cache / session pass-throughs surface here so the rule
// keeps its signal on `unserialize(trim($input))` /
// `unserialize(base64_decode($input))` shapes.
public function unserialize($input): void {
$this->payload = unserialize(trim($input));
}
}

View file

@ -0,0 +1,30 @@
<?php
// Regression for the PHP `if (!validator($x))` early-return narrowing fix
// (src/cfg/mod.rs detect_negation now recognises tree-sitter-php's
// `unary_op_expression` for `!`) PLUS the camelCase normalisation in
// classify_condition (src/taint/path_state.rs to_snake_lower). Before
// either fix, the camelCase validator name didn't classify as
// ValidationCall, and even if it did, the `!`-prefix wasn't seen as
// negation so the True branch (which is the rejection arm) was treated
// as the validated path, leaving `$url` un-validated past the
// early-return. Pairs with CVE-2026-33486 patched fixture.
class SafeImporter
{
public static function fetchRemote(): void
{
$url = $_REQUEST['url'];
if (!self::isSafeRemoteUrl($url)) {
return;
}
// Use file_get_contents (an SSRF sink that doesn't open a long-lived
// resource) so the regression specifically pins SSRF narrowing
// without conflating with state-resource-leak from fopen.
file_get_contents($url);
}
private static function isSafeRemoteUrl(string $u): bool
{
return true;
}
}

View file

@ -0,0 +1,40 @@
<?php
// `Serializable::unserialize($input)` magic-method body — the legacy
// PHP `Serializable` interface contract (deprecated since PHP 8.1).
// PHP itself invokes `\unserialize($attacker_bytes)` and then dispatches
// to this method during instance restoration; the body's `\unserialize($x)`
// call is part of the deserialization machinery and cannot be removed
// without breaking the interface. The actionable signal lives at the
// class level (the class implements deprecated `Serializable` — fix is
// to migrate to `__serialize` / `__unserialize`), not at this call
// site.
//
// Distilled from
// joomla/administrator/components/com_finder/src/Indexer/Result.php:488
// joomla/libraries/src/Input/Cli.php:112 joomla/libraries/src/Input/Input.php:210.
class IndexerResult implements \Serializable {
private array $data = [];
public function unserialize($serialized): void {
$this->data = unserialize($serialized);
}
}
class CliInput implements \Serializable {
public string $executable = '';
public array $args = [];
public array $options = [];
public function unserialize($input): void {
[$this->executable, $this->args, $this->options] = unserialize($input);
}
}
class CaseFolded implements \Serializable {
private mixed $payload = null;
public function UnSerialize($payload) {
$this->payload = unserialize($payload);
}
}

View file

@ -0,0 +1,17 @@
<?php
// Regression for the PHP class-method body analysis fix
// (declaration_list / interface_declaration / trait_declaration mapped to
// Kind::Block in src/labels/php.rs). Before the fix, taint never crossed
// `class { method { ... } }` because the body of `method` was never
// reached during function extraction, leaving `$_REQUEST → fopen` flows
// inside class methods invisible to taint analysis. Pairs with
// CVE-2026-33486 (roadiz/documents `DownloadedFile::fromUrl`).
class MediaImporter
{
public static function fetchRemote(): void
{
$url = $_REQUEST['url'];
fopen($url, 'r');
}
}