mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-30 20:39:39 +02:00
Performance and precision pass (#64)
This commit is contained in:
parent
c7c5e0f3a1
commit
fb698d2c27
97 changed files with 9932 additions and 517 deletions
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
17
tests/benchmark/corpus/php/ssrf/ssrf_class_method_fopen.php
Normal file
17
tests/benchmark/corpus/php/ssrf/ssrf_class_method_fopen.php
Normal 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');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue