# [CRIT] [GHSA / CRITICAL] CVE-2026-45697: Formie: Pre-authenticated server-side template injection in Hidden fields

**Source:** GitHub Security Advisories
**Published:** 2026-05-18
**Article:** https://github.com/advisories/GHSA-x7m9-mwc2-g6w2

## Threat Profile

Formie: Pre-authenticated server-side template injection in Hidden fields

### Impact
- Unauthenticated users could submit crafted values into Hidden fields (with Default value → Custom) that were evaluated as Twig during submission handling, which could lead to serious compromise of the Craft site (depending on template/sandbox behavior).
- Sites with public Formie forms that include at least one Hidden field with that configuration.
- No CP login for the reported chain.

### Patches
- [2.2.20]…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-45697`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1133** — External Remote Services
- **T1059.001** — Command and Scripting Interpreter: PowerShell
- **T1059.003** — Command and Scripting Interpreter: Windows Command Shell
- **T1059.004** — Command and Scripting Interpreter: Unix Shell
- **T1505.003** — Server Software Component: Web Shell

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Mass POSTs to Craft CMS Formie submission endpoint (CVE-2026-45697 SSTI exploitation scan)

`UC_273_1` · phase: **delivery** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count as Attempts, dc(Web.user_agent) as UAcount, values(Web.user_agent) as UAs, min(_time) as FirstSeen, max(_time) as LastSeen from datamodel=Web.Web where Web.http_method=POST (Web.url="*actions/formie/submissions/submit*" OR Web.url="*formie/submissions/submit*" OR Web.uri_query="*action=formie*submissions*submit*") by Web.src, Web.site | `drop_dm_object_name(Web)` | where Attempts >= 15 OR match(UAs, "(?i)(sqlmap|nuclei|tplmap|httpx|ffuf|gobuster|wfuzz|acunetix|nessus|burpsuite)") | sort - Attempts
```

### Web-server process (w3wp/php/nginx) spawns shell or LOLBin (post-SSTI RCE chain)

`UC_273_2` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count, min(_time) as firstSeen, max(_time) as lastSeen, values(Processes.process) as cmd, values(Processes.user) as user from datamodel=Endpoint.Processes where Processes.parent_process_name IN ("w3wp.exe","php-cgi.exe","php.exe","php-fpm","httpd.exe","httpd","nginx.exe","nginx") AND Processes.process_name IN ("cmd.exe","powershell.exe","pwsh.exe","sh","bash","dash","wscript.exe","cscript.exe","mshta.exe","certutil.exe","bitsadmin.exe","curl.exe","curl","wget.exe","wget","whoami.exe","whoami","id","uname","net.exe","ipconfig.exe") by host, Processes.user, Processes.parent_process_name, Processes.process_name, Processes.process | `drop_dm_object_name(Processes)` | where NOT match(user, "\\$$") | sort - lastSeen
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("w3wp.exe","php-cgi.exe","php.exe","php-fpm","php-fpm8.1","php-fpm8.2","php-fpm8.3","httpd.exe","httpd","nginx.exe","nginx","apache2")
| where FileName in~ ("cmd.exe","powershell.exe","pwsh.exe","sh","bash","dash","zsh","wscript.exe","cscript.exe","mshta.exe","certutil.exe","bitsadmin.exe","curl.exe","curl","wget.exe","wget","whoami.exe","whoami","id","uname","net.exe","ipconfig.exe","hostname","ifconfig")
| where AccountName !endswith "$"
| where InitiatingProcessAccountName !in~ ("system","local service","network service")
| project Timestamp, DeviceName, AccountName,
          ParentImage = InitiatingProcessFolderPath,
          ParentCmd   = InitiatingProcessCommandLine,
          ChildImage  = FolderPath,
          ChildCmd    = ProcessCommandLine,
          SHA256
| order by Timestamp desc
```

### PHP / IIS web-server writes .php/.phtml/.phar to webroot (post-SSTI webshell drop)

`UC_273_3` · phase: **install** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count, min(_time) as firstSeen, max(_time) as lastSeen, values(Filesystem.file_name) as files, values(Filesystem.process_name) as procs from datamodel=Endpoint.Filesystem where (Filesystem.process_name IN ("w3wp.exe","php-cgi.exe","php.exe","php-fpm","httpd.exe","httpd","nginx.exe","nginx","apache2")) AND (Filesystem.file_name="*.php" OR Filesystem.file_name="*.phtml" OR Filesystem.file_name="*.phar" OR Filesystem.file_name="*.aspx" OR Filesystem.file_name="*.inc") AND (Filesystem.file_path="*\\wwwroot\\*" OR Filesystem.file_path="*\\httpdocs\\*" OR Filesystem.file_path="*\\web\\*" OR Filesystem.file_path="*\\public\\*" OR Filesystem.file_path="*\\cpresources\\*" OR Filesystem.file_path="*\\templates\\*" OR Filesystem.file_path="*/var/www/*" OR Filesystem.file_path="*/srv/www/*" OR Filesystem.file_path="*/usr/share/nginx/*") by host, Filesystem.user, Filesystem.process_name, Filesystem.file_name, Filesystem.file_path | `drop_dm_object_name(Filesystem)` | sort - lastSeen
```

**Defender KQL:**
```kql
let webroots = dynamic(["\\wwwroot\\","\\httpdocs\\","\\web\\","\\public\\","\\cpresources\\","\\templates\\","/var/www/","/srv/www/","/usr/share/nginx/","/home/forge/","/home/craft/"]);
DeviceFileEvents
| where Timestamp > ago(7d)
| where ActionType in ("FileCreated","FileModified","FileRenamed")
| where InitiatingProcessFileName in~ ("w3wp.exe","php-cgi.exe","php.exe","php-fpm","php-fpm8.1","php-fpm8.2","php-fpm8.3","httpd.exe","httpd","nginx.exe","nginx","apache2")
| where FileName endswith ".php" or FileName endswith ".phtml" or FileName endswith ".phar" or FileName endswith ".aspx" or FileName endswith ".inc"
| where FolderPath has_any (webroots)
| where not(FolderPath has_any ("\\storage\\runtime\\","\\vendor\\","\\.composer\\","/storage/runtime/","/vendor/","\\node_modules\\"))
| project Timestamp, DeviceName, ActionType, FolderPath, FileName, SHA256,
          InitiatingProcessFileName, InitiatingProcessAccountName,
          InitiatingProcessCommandLine, InitiatingProcessFolderPath
| order by Timestamp desc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-45697`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 4 use case(s) fired, 6 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
