Skip to content
Open
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions docs/blog/posts/blackbox-found-vulnerability-in-php.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
authors: [baptouuuu]
date: 2026-08-08
---

# BlackBox found a vulnerability in PHP

This happened early July when working a simple dependency upgrade on [`innmind/filesystem`](https://github.com/Innmind/Filesystem/pull/32).

Long story short: a bug in PHP's `8.5` `Uri\WhatWg\Url::__construct()` allowed to extract part of the process memory.

But let's backtrack a bit.

<!-- more -->

## Finding the bug

Innmind handles URLs via the package [`innmind/url`](https://github.com/innmind/url). Up to its `5.0` version it used [`league/uri-parser`](https://packagist.org/packages/league/uri-parser) for the parsing, but it's been abandoned for quite a while. So when PHP `8.5` released with the new `Uri` APIs, `innmind/url` released a `5.1` version using them exclusively (meaning PHP `8.4` support was dropped).

Like many Innmind packages it uses [`innmind/black-box`](https://github.com/innmind/blackbox) to test the package. So to make sure `innmind/url` handles a lot of cases it uses BlackBox's capability to generate random data. So far so good.

Fast forward a few months after the release of [`innmind/foundation` v2](hardening-api-consistency.md). The foundation packages were in place stable enough to decide to update this documentation. But BlackBox was still in v6 with lots of deprecated code and a significant backlog of new features and BC breaks for an upcoming v7.

So instead of updating this documentation twice, the goal was to do the [v7](https://github.com/Innmind/BlackBox/releases/tag/7.0.0) update all the foundation packages that expose fixtures and then update this documentation.

So in `innmind/url` version [`5.3`](https://github.com/Innmind/Url/releases/tag/5.3.0) it updated BlackBox to its v7 and flag it as conflictual with its v6 to avoid dependent packages to use the fixtures with an incompatible version of BlackBox.

That meant that when updating `innmind/filesystem`, which depends on `innmind/url`, to BlackBox v7 it also had to use `innmind/url` `5.3` and thus PHP `8.5`.

The [PR](https://github.com/Innmind/Filesystem/pull/32) was opened on May 14 with the CI failing. `innmind/filesystem` goes all the way on Property Based Testing with BlackBox and generate complex sequences of actions and data to make sure everything works as expected. The CI failure output seemed non trivial and was left as is for about 2 months due to a lack of time to work on it.

Then came early July, time to fix the CI.

The CI bug was reproducible locally. While debugging underlying issues a test failed with this output:

![](../../../../assets/blackbox-security-flaw-php/memory-dump.png)

That's BlackBox own code.

The first reaction was: that's strange, there must be a bug in the test!

When looking at the stack strace and the generated input data, it showed that `innmind/filesystem` was trying to build a `Innmind\Url\Path` with lots of different characters and emojis. But BlackBox for some reason didn't [shrink](https://innmind.org/BlackBox/preface/terminology/#shrinking) further this path `string`. So I did the process by hand.

Turned out that this was the minimal `string` that made the test fail:

```php
$path = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa😨';
```

If you didn't scroll, it's `1010` `a`s followed by `😨`.

Inside `innmind/url` this path was fed to `#!php new \Uri\WhatWg\Url($path, new \Uri\WhatWg\Url('http://a.org'))`.

Prior to PHP `8.5.8` if there's a non encoded emoji after the 1010th character in the path then there's an internal bug that lead to leaking part of the process memory.

And if you played with the number of characters before the emoji then you could move around in the exposed memory.

## Reporting the vulnerability to PHP

Before submitting the issue I looked at [PHP's documentation](https://github.com/php/php-src/security) to do this properly.

But due to some phrasing I wasn't sure this would be considered as a vulnerability. But on [Romane Ledru](https://www.linkedin.com/in/romane-ledru/)'s advice I went ahead and reported it the following day on July 4.

The very same day I got a kind response from [Alexandre Daubois](https://www.linkedin.com/in/alexandre-daubois/) explaining that it was a bug in Lexbor, used for URL parsing, and had been [fixed by Ilija Tovilo](https://github.com/php/php-src/commit/0cd59c952175eb82f4fd42d43f63ac4f400979d2) on July 1st and released in PHP `8.5.8` on July 3rd.

## Conclusion

Even though the vulnerability had just been fixed, the experience was interesting.

This was the first I had to report a security vulnerability. There's the self doubt initially of "Is this really a security problem?", then the "I don't want to put extra work on PHP team if it doesn't pan out" and finally the submit form that looks a bit scary.

Before this event BlackBox had already found plenty of user land bugs. But I never foresaw it would find a bug in PHP itself (1).
{.annotate}

1. or more precisely in one of its depedencies.

BlackBox, and Property Based Testing, can be infuriating at times when it keeps telling you your code doesn't work. But everytime it finds this kind of bug it becomes more addictive :star_struck: .