BOOK THIS SPACE FOR AD
ARTICLE ADLet’s talk about a security research I conducted a few months ago. As you might know, I like hunting for 0-days in WordPress plugins, but this time, I targeted a big player in the WordPress ecosystem: the WooCommerce plugin.
When I first began hunting for 0-days in WordPress Plugins, I noticed that WooCommerce has several sub-plugins that extend its functionality, and I knew I should eventually take a closer look at the WooCommerce ecosystem. I saw this as a great opportunity to discover some vulnerabilities.
Indeed, WooCommerce had over 7 million active installations when writing this write-up, making it the most popular e-commerce plugin and ranking in the top two most popular WordPress plugins, according to the WordPress website: https://wordpress.com/blog/2024/01/05/10-most-popular-plugins-wordpress-dot-com/
In this write-up, we will focus on CVE-2024–9944, a 0-day I identified on WooCommerce core in May 2024.
CVE-2024–9944 is an unauthenticated stored HTML injection vulnerability I identified while testing the WooCommerce plugin. I discovered that a malicious user could inject harmful HTML into the “Order Notes” field when placing an order. The injected HTML is executed in two distinct locations:
Order Confirmation Page: When an order is submitted, the order confirmation page is generated with a unique URL. An attacker can inject malicious HTML tags into the “Order Notes,” which would then appear on the confirmation page. Since this is a unique URL, the attacker could use it to launch phishing attacks or other social engineering tactics.New Order Confirmation Email: When an order is placed, the administrator of the e-commerce site receives a notification via email. The injected HTML in the order notes is rendered in the email body, potentially leading to phishing attacks or social engineering attempts, this time directly targeting administrators.It’s important to note that the “Order Notes” field is enabled by default in WooCommerce, so there is a high likelihood that websites running versions ≤ 9.0.2 are still affected by this bug. The issue has been resolved in version 9.1.0 (July 2024).
Readme.txt on WooCommerce version 9.1.0
When I first discovered this bug, I found it through a dynamic analysis of the plugin. I then reviewed the code to see if I could escalate the issue further, potentially turning it into a stored XSS. After some investigation, I concluded that I could only exploit it as an HTML injection, as WooCommerce was using the correct functions to block JavaScript execution.
As I mentioned earlier, in all WooCommerce versions ≤ 9.0.2, it’s possible to inject HTML code into the “Order Notes” field. To do this, all you need to do is to add a comment by selecting “Add a note to your order” option and inject any HTML code you want.
A unique URL is generated for the order confirmation page when the order is placed. On this page, the injected HTML tag will be executed and displayed.
The URL looks something like this:
https://<DOMAIN>/?page_id=15&order-received=36&key=wc_order_X3sr1cPV47oRA
I believe this unique URL is generated so the user can always access their order confirmation page if needed. In that sense, it’s a static URL. Consequently, an attacker could share this URL with others, and the injected HTML would always be executed when accessed.
From the administrator’s perspective, they will receive the following email notifications if email alerts are enabled.
As we can see in the email, the injected HTML is rendered in the “Note” section, demonstrating that administrators are also impacted through the order confirmation email.
Yes, it was simple as that. I was pretty surprised how this bug had never been reported before.
By analyzing WooCommerce’s codebase in versions 9.0.2 and 9.1.0 (the version where the issue was patched), I observed three changes related to this vulnerability:
Location 1: templates/order/order-details.php
Version ≥ 9.0.2
Function Used: wp_kses_post()
This function is a safe version of wp_kses(), which strips out any potentially harmful HTML but allows a standard set of safe HTML tags like <br>, <p>, <strong>, etc. It’s commonly used to sanitize user input or output in WordPress, particularly when HTML is expected to be present in the content, like in posts or comments.From Version 9.1.0
Function Used: wp_kses()
This function allows for more control over which HTML tags are permitted in the output. In this case, the array() argument indicates that no HTML tags are allowed at all, so it strips out all HTML. As a result, the output will only include plain text with no HTML formatting.Key Difference:
First code (wp_kses_post()): Allows some safe HTML tags in the customer note (like <br>, <p>, etc.).Second code (wp_kses(array())): Strips all HTML tags, leaving only plain text.Location 2: templates/emails/email-order-details.php
Version ≥ 9.0.2
As we can observe, they once again use the wp_kses_post() function here, which strips out any potentially harmful HTML but allows a standard set of safe HTML tags like <p>, <br>, <strong>, and others.
From Version 9.1.0
Function Used: wp_kses(nl2br(wptexturize($order->get_customer_note())),array())
Similar to the fix they implemented on order-details.php, they also applied the same patch using wp_kses(), allowing for more control over which HTML tags are permitted in the output. In this case, the array() argument indicates that no HTML tags are allowed at all, so it strips out all HTML. As a result, the output will only include plain text with no HTML formatting.
Location 3: templates/emails/plain/email-order-details.php
Version ≥ 9.0.2
Function Used: wp_kses_post( wptexturize( $order->get_customer_note() ) )
Once again, we see the same code pattern:
wp_kses_post() allows safe HTML tags to be preserved in the customer note (like <p>, <br>, etc.), so if the customer note contains HTML, it will be kept as long as it's “safe”.
From Version 9.1.0
Function Used: wp_kses( wptexturize( $order->get_customer_note() ), array() )
As we can see, WooCommerce used the same strategy to mitigate this issue. They used wp_kses() to strip all HTML tags from the customer note, combined with the array() function, which ensures that no HTML tags are allowed at all, fully mitigating the issue.
Research Timeline:
13th May 2024: Bug identified in WooCommerce version 8.8.3 and reported to Automattic via HackerOne.11th July 2024: The issue was fixed and released by WooCommerce in version 9.1.0.31st August 2024: Report closed and marked as solved on HackerOne.14th October 2024: CVE assigned to the bug.17th October 2024: Write-up publication.References:
WordPress WooCommece Page: https://wordpress.org/plugins/woocommerce/
WooCommerce 9.1.0 source code: https://github.com/woocommerce/woocommerce/releases/tag/9.1.0
WooCommerce 9.0.2 source code (last version vulnerable to this issue): https://github.com/woocommerce/woocommerce/releases/tag/9.0.2
Wordfence CVE page: https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/woocommerce/woocommerce-902-unauthenticated-html-injection
To mitigate this issue, simply update WooCommerce to the latest version.
I hope this write-up has helped you better understand all the aspects of CVE-2024–9944. Feel free to reach out with any questions. You can find me on Twitter or LinkedIn.
Twitter: @dropn0w
LinkedIn: Pedro Paniago
Keep learning, keep hacking!