| @@ -197,8 +197,10 @@ | ||
| 197 | 197 | return false; |
| 198 | 198 | } |
| 199 | 199 | |
| 200 | 200 | /** |
| 201 | + * @since 4.16.7.2 Returns false instead of the raw serialized string when an object is detected | |
| 202 | + * @since 4.16.6 Returns $data when $unserializedData constins __PHP_Incomplete_Class | |
| 201 | 203 | * @since 3.17.2 |
| 202 | 204 | */ |
| 203 | 205 | public static function safeUnserialize($data) |
| 204 | 206 | { |
| @@ -215,8 +217,12 @@ | ||
| 215 | 217 | * this option is the same as defining it as true: PHP will attempt to instantiate objects of any class. |
| 216 | 218 | */ |
| 217 | 219 | $unserializedData = @unserialize(trim($data), ['allowed_classes' => false]); |
| 218 | 220 | |
| 221 | + if (self::containsPhpIncompleteClass($unserializedData)) { | |
| 222 | + return false; | |
| 223 | + } | |
| 224 | + | |
| 219 | 225 | /* |
| 220 | 226 | * In case the passed string is not unserializeable, false is returned. |
| 221 | 227 | * |
| 222 | 228 | * @see https://www.php.net/manual/en/function.unserialize.php |
| @@ -222,8 +228,35 @@ | ||
| 222 | 228 | * @see https://www.php.net/manual/en/function.unserialize.php |
| 223 | 229 | */ |
| 224 | 230 | |
| 225 | 231 | return ! $unserializedData && ! self::containsSerializedDataRegex($data) ? $data : $unserializedData; |
| 232 | + } | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * Recursively checks if the given data contains any __PHP_Incomplete_Class instance, | |
| 236 | + * which is what unserialize() produces for classes not present in allowed_classes. | |
| 237 | + * | |
| 238 | + * @since 4.16.6 | |
| 239 | + * | |
| 240 | + * @param mixed $data Data to check, can be any type. | |
| 241 | + * | |
| 242 | + * @return bool True if a __PHP_Incomplete_Class instance is found at any nesting level. | |
| 243 | + */ | |
| 244 | + public static function containsPhpIncompleteClass($data): bool | |
| 245 | + { | |
| 246 | + if ($data instanceof \__PHP_Incomplete_Class) { | |
| 247 | + return true; | |
| 248 | + } | |
| 249 | + | |
| 250 | + if (is_array($data) || is_object($data)) { | |
| 251 | + foreach ((array)$data as $value) { | |
| 252 | + if (self::containsPhpIncompleteClass($value)) { | |
| 253 | + return true; | |
| 254 | + } | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | + return false; | |
| 226 | 259 | } |
| 227 | 260 | |
| 228 | 261 | /** |
| 229 | 262 | * Avoid insecure usage of `unserialize` when the data could be submitted by the user. |