Summary
CVE-2021-29447 is an Authenticated XML External Entity (XXE) vulnerability exploitable in WordPress versions 5.6 to 5.7.1. The issue affects the Media Library, which allows authenticated users (like contributors or authors) to upload media files.
WordPress versions 5.6 to 5.7 were vulnerable to an XML External Entity (XXE) attack in the Media Library due to improper handling of XML external entities in the ID3 library, which parses audio metadata. This vulnerability, triggered by file uploads from users with the ability to upload files, was reintroduced with PHP 8’s deprecation of libxml_disable_entity_loader(). The issue was addressed in WordPress 5.7.1, which reintroduced the protective function to prevent XXE attacks. Users should update to version 5.7.1 or later to mitigate the risk.
Technical Details
Affected Component - Audio Metadata Parsing
When a media file is uploaded via the WordPress Media Library, WordPress attempts to extract metadata such as title, artist, album, and embedded comments. For audio files, this is done using the function wp_read_audio_metadata(), which internally calls the getID3 library.
getID3() is a third-party PHP library used by WordPress to analyze and extract metadata from audio files — including tags, encoding information, and embedded XMP (XML-based metadata). One type of metadata that audio files can carry is XMP (Extensible Metadata Platform) — a standardized format based on XML. This becomes dangerous if malicious XML is used.
The vulnerability exists because WordPress and getID3 did not securely configure the XML parser, which is responsible for reading XMP metadata.
More specifically:
- XML parsing was done using simplexml_load_string() without disabling the resolution of external entities.
- In PHP 8 and above, changes to the libxml extension's behavior made it possible to load external entities by default.
- As a result, a specially crafted XML payload could be used to force the server to read arbitrary files or make requests to internal services.
What is XML External Entity (XXE) attack?
Before diving into the specifics of the vulnerability, it’s important to understand the type of attack it enabled: an XML External Entity (XXE) attack.
XXE is a type of vulnerability that occurs when an application parses XML input without properly restricting special XML features called "entities." These entities can reference external files or even remote URLs.
An attacker can craft malicious XML content that tricks the application into:
- Reading local files (e.g., /etc/passwd)
- Making requests to internal services (SSRF)
- In rare cases, executing denial of service or remote code execution
The Root Cause - Unsafe XML Parsing in PHP 8+
In PHP 8 and later, there were changes to how XML entity loading is handled:
- Previously, developers could globally disable entity loading using libxml_disable_entity_loader(true)
- In PHP 8+, that function became deprecated and lost its effect in some cases
As a result, unless explicitly prevented, XML parsing in PHP 8+ may allow external entity resolution, even if it was blocked in earlier PHP versions.
Vulnerable Code (Before Patch)
In the official patch commit, we can see that WordPress added safeguards to prevent XXE by securing the XML parser before processing any user-supplied data.
Here’s a simplified version of what the old code looked like:
This code uses simplexml_load_string() without any flags to restrict dangerous XML features.
By default, SimpleXML allows DTDs and external entities, which means the following malicious code could be executed, leading to sensitive file disclosure:
Exploitation
Step1. Login to the Wordpress dashboard with Author privileges and navigate to the Media menu on the left side of the dashboard. Click on it and you’ll have the option to “Add New” media to the collection.
This is the starting point. Here, WordPress allows us to upload audio files such as .wav.
Step2. Instead of a normal audio file, the attacker uploads a crafted file named payload.wav.
This file contains malicious XML metadata that abuses the vulnerable XML parser.
Content of payload.wav metadata:
- This metadata defines a DOCTYPE with external entities.
- It tells the parser to fetch additional XML instructions from the attacker’s server (ezz.dtd).
Step3. Attacker then hosts the External DTD file on their server namely xxe.dtd
Here’s what it does:
- %file — reads /etc/passwd from the server (sensitive local file).
- %init — defines another entity %trick that sends the content of %file back to the attacker’s server as part of a request.
Step4. When WordPress attempts to parse the uploaded payload.wav for metadata, it processes the malicious XML.
This causes WordPress to:
- Fetch ezz.dtd from the attacker’s server.
- Expand the %file entity to read /etc/passwd.
- Send the base64-encoded file contents back to the attacker in an HTTP request.
On the attacker’s HTTP server logs, the exfiltrated data can be observed.

Step5. The attacker then decodes the base64 response to recover the original /etc/passwd file:
echo "<base64-string>" | base64 --decode

Mitigation:
- Update to the Latest WordPress Version
Ensure your WordPress installation is updated to version 5.7.1 or newer. This version includes a fix that prevents the use of insecure XML parsing when processing audio metadata, effectively closing the XXE attack vector. - Ensure PHP 8 Compatibility
Starting with PHP 8, the function libxml_disable_entity_loader(true) is deprecated and has no effect. WordPress 5.7.1 adapts to this change by modifying its XML parsing behavior to avoid unsafe flags like LIBXML_NOENT. Ensure your site runs this version (or newer) to maintain secure behavior in PHP 8+ environments. - Disable External Entity Loading
If using XML parsing in custom code, avoid using the LIBXML_NOENT flag and ensure external entity loading is properly disabled. In PHP versions prior to 8, this can still be done with libxml_disable_entity_loader(true).
Reference :
https://www.sonarsource.com/blog/wordpress-xxe-security-vulnerability/
https://wpscan.com/vulnerability/cbbe6c17-b24e-4be4-8937-c78472a138b5/