Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion classes/Visualizer/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,36 @@ public static function decode_content( $content ) {
if ( ! is_string( $content ) ) {
return false;
}
return self::strip_incomplete_objects( unserialize( trim( $content ), array( 'allowed_classes' => false ) ) );
$value = unserialize( trim( $content ), array( 'allowed_classes' => false ) );
if ( self::contains_references( $value ) ) {
return false;
}
return self::strip_incomplete_objects( $value );
}

/**
* Check decoded arrays for references before recursively processing them.
*
* Cyclic serialized arrays necessarily contain a reference. Rejecting all
* references also prevents shared references from becoming cycles later,
* so strip_incomplete_objects() cannot recurse without terminating.
*
* @param mixed $value The decoded value.
* @return bool Whether the value contains an array reference.
*/
private static function contains_references( $value ) {
if ( ! is_array( $value ) ) {
return false;
}
foreach ( array_keys( $value ) as $key ) {
if ( null !== ReflectionReference::fromArrayElement( $value, $key ) ) {
return true;
}
if ( is_array( $value[ $key ] ) && self::contains_references( $value[ $key ] ) ) {
return true;
}
}
return false;
}

/**
Expand Down
19 changes: 19 additions & 0 deletions tests/test-security-object-injection.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,25 @@ public function test_decode_content_does_not_instantiate_objects() {
);
}

/**
* The shared decoder must reject cyclic serialized arrays without recursing.
*
* The allowed_classes guard only blocks objects; a self-referential array
* (R:/r: token) survives it and would drive strip_incomplete_objects() into
* unbounded recursion. decode_content() must reject it up front.
*/
public function test_decode_content_rejects_cyclic_arrays() {
$this->assertFalse(
Visualizer_Module::decode_content( 'a:1:{i:0;R:1;}' ),
'decode_content() must reject cyclic arrays.'
);
$this->assertSame(
array( 'marker' => 'R:1;' ),
Visualizer_Module::decode_content( serialize( array( 'marker' => 'R:1;' ) ) ),
'Reference-like text inside strings must remain valid.'
);
}

/**
* The Utility pie/polarArea render palette call site must not instantiate objects.
*
Expand Down
Loading