Skip to content

Keep the object alive across jsonSerialize() in json_encode()#22469

Open
iliaal wants to merge 1 commit into
php:PHP-8.5from
iliaal:fix/gh21024-json-jsonserialize-uaf
Open

Keep the object alive across jsonSerialize() in json_encode()#22469
iliaal wants to merge 1 commit into
php:PHP-8.5from
iliaal:fix/gh21024-json-jsonserialize-uaf

Conversation

@iliaal

@iliaal iliaal commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

json_encode() can use-after-free a JsonSerializable object when its jsonSerialize() triggers a user error handler that frees the object, for example by nulling a reference that aliases the encoded array slot. php_json_encode_serializable_object() holds a raw pointer to the object across the call and then reads its recursion guard and compares identity against the return value.

Fix: hold a reference on the object across the call. The array path already guards against this with a ZVAL_COPY ("Avoid modifications (and potential freeing) of the array... when a jsonSerialize() method is invoked"); the JsonSerializable object path did not.

php_json_encode_serializable_object() holds a raw pointer to the object
across the jsonSerialize() call, then reads its recursion guard and
compares the returned value's identity against it. A user error handler
triggered from jsonSerialize() can drop the last reference to the object,
for example by nulling a reference that aliases the encoded array slot,
freeing it before those reads and causing a use-after-free.

Hold a reference on the object across the call. The array path already
guards against this with a ZVAL_COPY; the JsonSerializable object path
did not. Same use-after-free class as phpGH-21024 in var_dump().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant