Safeguard
Security

CVE-2022-31630: The PHP GD imageloadfont() Out-of-Bounds Read Explained

CVE-2022-31630 is an out-of-bounds read in PHP's GD extension triggered through imageloadfont(). Here are the affected versions, real impact, and the fix.

Aisha Rahman
Security Analyst
5 min read

CVE-2022-31630 is an out-of-bounds read vulnerability in PHP's GD image extension, triggered when a maliciously crafted font file is loaded with imageloadfont() and later used with imagechar(). The result can be a crash or the disclosure of memory contents beyond the allocated buffer. If you run PHP applications that let users upload or supply font files to GD, this one is worth verifying against your installed version.

What goes wrong

The GD extension bundled with PHP includes imageloadfont(), a function that reads a custom bitmap font file into a gdFont structure so text can be drawn onto an image with imagechar() or imagestring().

In the affected versions, imageloadfont() does not validate the font file's header fields strictly enough. A specially crafted font can drive a zero-byte memory allocation for gdFont.data. Later, when that font is passed to imagechar() to render a character, the code reads past the end of the tiny (or empty) buffer — an out-of-bounds read. Depending on memory layout, that either crashes the process or leaks adjacent heap memory into the output.

This is a memory-safety bug in native C code, not a logic flaw in userland PHP, which is why the fix has to come from the PHP runtime itself rather than something you can guard in your own code.

Affected versions

CVE-2022-31630 affects PHP versions prior to 7.4.33, 8.0.25, and 8.1.12. The bug was introduced in the PHP 7.4 line — versions before 7.4 do not carry it.

The fixed releases are:

  • PHP 7.4.33
  • PHP 8.0.25
  • PHP 8.1.12

Upgrade to one of these or later. Note that 7.4 and 8.0 are both past their end-of-life for community security support, so if you are still on those lines the real remediation is moving to a currently supported major version rather than chasing individual patches.

Check your running version precisely, since a distro package version string can differ from the upstream PHP version:

php -v
php -r 'echo PHP_VERSION, PHP_EOL;'

And confirm GD is actually enabled, because if it is not, this function is not reachable in your build:

php -m | grep -i gd
php -r 'var_dump(function_exists("imageloadfont"));'

How exploitable is it in practice?

The severity here depends heavily on whether attacker-controlled font files ever reach imageloadfont(). imageloadfont() loads a custom GD-format bitmap font — it is not something most applications call at all, and even fewer call with a user-supplied path.

Walk the data flow honestly:

  1. Does your application call imageloadfont() anywhere?
  2. If so, can the font file path or contents be influenced by an untrusted user?
  3. Is the loaded font then used with imagechar() or a related drawing call?

If all three are true, you have a real exploitable path and should prioritize the upgrade. If your code only ever loads a fixed, trusted font shipped with the application, the practical risk is low — but you should still patch, because the underlying runtime is vulnerable and a future code change could expose the path.

Remediation

The clean fix is upgrading PHP:

# Debian/Ubuntu example — use your distro's security-patched package
sudo apt update && sudo apt install --only-upgrade php php-gd

# Verify afterward
php -v

For containerized apps, rebuild on a patched base image tag rather than upgrading in place, so the fix persists across redeploys:

# Pin to a patched, supported PHP version
FROM php:8.1.12-fpm
# ...

If you cannot upgrade immediately, the interim mitigation is to make sure no untrusted input reaches imageloadfont(): never build the font path from user input, and don't accept uploaded font files for GD rendering. That reduces exposure but is not a substitute for patching the runtime.

Keeping runtime CVEs visible

Runtime and system-level dependencies like the PHP interpreter and its extensions are easy to lose track of, because they don't live in composer.json alongside your application packages. A build that pins FROM php:8.1.7-fpm will happily keep shipping a vulnerable interpreter long after 8.1.12 is out, and nothing in your app dependency file will complain.

Scanning container images and system packages, not just language-level manifests, is how you catch this. An SCA and container scanning workflow that inventories the interpreter version alongside your Composer packages will flag an out-of-date PHP base image; a tool such as Safeguard can raise CVE-2022-31630 against an image still pinned to a pre-7.4.33 or pre-8.1.12 PHP. Pair that with base-image update discipline and this class of finding stops accumulating silently. If you're formalizing an upgrade cadence, our security academy covers dependency lifecycle basics.

FAQ

What does CVE-2022-31630 let an attacker do?

It allows an out-of-bounds read in the GD extension, which can crash the PHP process or leak adjacent memory contents. It is a memory-disclosure and availability issue rather than direct remote code execution.

Which PHP versions fix CVE-2022-31630?

PHP 7.4.33, 8.0.25, and 8.1.12 (and later) contain the fix. Versions before PHP 7.4 were never affected because the bug was introduced in the 7.4 line.

Am I affected if my app never calls imageloadfont()?

Your runtime is technically vulnerable, but the specific attack path is not reachable unless imageloadfont() is called with attacker-influenced input and the result is drawn. Patch regardless, since a future code change could open the path.

How do I check my current PHP and GD status?

Run php -v for the version and php -m | grep -i gd to confirm the GD extension is loaded. Use php -r 'var_dump(function_exists("imageloadfont"));' to check the specific function is available in your build.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.