CVE-2025-66294
Grav is vulnerable to RCE via SSTI through Twig Sandbox Bypass
Grav is a file-based Web platform. Prior to 1.8.0-beta.27, a Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method. This vulnerability is fixed in 1.8.0-beta.27.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.7
Grav is vulnerable to RCE via SSTI through Twig Sandbox Bypass
Grav is a file-based Web platform. Prior to 1.8.0-beta.27, a Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method. This vulnerability is fixed in 1.8.0-beta.27.
- Record
CVE-2025-66294- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-94, CWE-1336
- Updated
- 2026-11-02
EUVDEUVD-2025-200081
8.7
Grav is a file-based Web platform. Prior to 1.8.0-beta.27, a Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method. This vulnerability is fixed in 1.8.0-beta.27.
- Record
EUVD-2025-200081- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-662m-56v4-3r8f
8.7
Grav is vulnerable to RCE via SSTI through Twig Sandbox Bypass
Summary
A Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method.
Important
-
First of all this vulnerability is due to weak sanitization in the method
clearDangerousTwig, so any other class that calls it indirectly through for example$twig->processStringto sanitize code is also vulnerable. -
For this report, we will need the official Form and Admin plugin installed, also I will be chaining this with another vulnerability to allow an editor which is a user with only pages permissions to edit the process section of a form.
-
I made another report for the other vulnerability which is a Broken Access Control which allows a user with full permission for pages to change the process section by intercepting the request and modifying it.
Permissions Needed
- The main case for this vulnerability is an editor which can unconditionally takeover the whole system through creating a vulnerable form.
- Second case is as an unauthenticated user, so if the form exists already and accepts user input and puts it through
evaluate_twig, a guest can takeover the system.
Details
When we make a form with a process section and a message action, when the form is submitted we get to deal with onFormProcess in form.php through the message case:
case 'message':
$translated_string = $this->grav['language']->translate($params);
$vars = array(
'form' => $form
);
/** @var Twig $twig */
$twig = $this->grav['twig'];
$processed_string = $twig->processString($translated_string, $vars);
$form->message = $processed_string;
break;
Which takes our parameters as in our action values, like in our case the value of our message action and sends it to processString which then calls the method cleanDangerousTwig from Security.php, now here's where we find the vulnerability is caused by two things:
- First of all is weak regex which doesn't account for nested function calls, which allows us to bypass this function's sanitization
- Second issue which is the
evaluateandevaluate_twigfunctions which are allowed, and since we can call Twig syntax from inside them, it will lead to nested function calls which we can bypass and thus execute arbitrary payloads.
public static function cleanDangerousTwig(string $string): string
{
if ($string === '') {
return $string;
}
$bad_twig = [
'twig_array_map',
'twig_array_filter',
'call_user_func',
'registerUndefinedFunctionCallback',
'undefined_functions',
'twig.getFunction',
'core.setEscaper',
'twig.safe_functions',
'read_file',
];
// This allows for a payload like {{ evaluate("read_file('/etc/passwd')") }}
$string = preg_replace('/(({{\s*|{%\s*)[^}]*?(' . implode('|', $bad_twig) . ')[^}]*?(\s*}}|\s*%}))/i', '{# $1 #}', $string);
return $string;
}
PoC
First to showcase how the function handles the payload, I built a small php program that replicates the behavior of cleanDangerousTwig:
<?php
function cleanDangerousTwig(string $string): string
{
if ($string === '') {
return $string;
}
$bad_twig = [
'twig_array_map',
'twig_array_filter',
'call_user_func',
'registerUndefinedFunctionCallback',
'undefined_functions',
'twig.getFunction',
'core.setEscaper',
'twig.safe_functions',
'read_file',
];
$string =…
- Record
GHSA-662m-56v4-3r8f- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-94, CWE-1336
- Updated
- 2026-11-02
NVD
8.7
Grav is a file-based Web platform. Prior to 1.8.0-beta.27, a Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method. This vulnerability is fixed in 1.8.0-beta.27.
- Record
CVE-2025-66294- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-94, CWE-1336
- Updated
- 2026-11-02
OSV
8.7
Grav is vulnerable to RCE via SSTI through Twig Sandbox Bypass
Grav is a file-based Web platform. Prior to 1.8.0-beta.27, a Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method. This vulnerability is fixed in 1.8.0-beta.27.
- Record
CVE-2025-66294- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-1336, CWE-94
- Updated
- 2026-11-02
OSVGHSA-662m-56v4-3r8f
8.7
Grav is vulnerable to RCE via SSTI through Twig Sandbox Bypass
Summary
A Server-Side Template Injection (SSTI) vulnerability exists in Grav that allows authenticated attackers with editor permissions to execute arbitrary commands on the server and, under certain conditions, may also be exploited by unauthenticated attackers. This vulnerability stems from weak regex validation in the cleanDangerousTwig method.
Important
-
First of all this vulnerability is due to weak sanitization in the method
clearDangerousTwig, so any other class that calls it indirectly through for example$twig->processStringto sanitize code is also vulnerable. -
For this report, we will need the official Form and Admin plugin installed, also I will be chaining this with another vulnerability to allow an editor which is a user with only pages permissions to edit the process section of a form.
-
I made another report for the other vulnerability which is a Broken Access Control which allows a user with full permission for pages to change the process section by intercepting the request and modifying it.
Permissions Needed
- The main case for this vulnerability is an editor which can unconditionally takeover the whole system through creating a vulnerable form.
- Second case is as an unauthenticated user, so if the form exists already and accepts user input and puts it through
evaluate_twig, a guest can takeover the system.
Details
When we make a form with a process section and a message action, when the form is submitted we get to deal with onFormProcess in form.php through the message case:
case 'message':
$translated_string = $this->grav['language']->translate($params);
$vars = array(
'form' => $form
);
/** @var Twig $twig */
$twig = $this->grav['twig'];
$processed_string = $twig->processString($translated_string, $vars);
$form->message = $processed_string;
break;
Which takes our parameters as in our action values, like in our case the value of our message action and sends it to processString which then calls the method cleanDangerousTwig from Security.php, now here's where we find the vulnerability is caused by two things:
- First of all is weak regex which doesn't account for nested function calls, which allows us to bypass this function's sanitization
- Second issue which is the
evaluateandevaluate_twigfunctions which are allowed, and since we can call Twig syntax from inside them, it will lead to nested function calls which we can bypass and thus execute arbitrary payloads.
public static function cleanDangerousTwig(string $string): string
{
if ($string === '') {
return $string;
}
$bad_twig = [
'twig_array_map',
'twig_array_filter',
'call_user_func',
'registerUndefinedFunctionCallback',
'undefined_functions',
'twig.getFunction',
'core.setEscaper',
'twig.safe_functions',
'read_file',
];
// This allows for a payload like {{ evaluate("read_file('/etc/passwd')") }}
$string = preg_replace('/(({{\s*|{%\s*)[^}]*?(' . implode('|', $bad_twig) . ')[^}]*?(\s*}}|\s*%}))/i', '{# $1 #}', $string);
return $string;
}
PoC
First to showcase how the function handles the payload, I built a small php program that replicates the behavior of cleanDangerousTwig:
<?php
function cleanDangerousTwig(string $string): string
{
if ($string === '') {
return $string;
}
$bad_twig = [
'twig_array_map',
'twig_array_filter',
'call_user_func',
'registerUndefinedFunctionCallback',
'undefined_functions',
'twig.getFunction',
'core.setEscaper',
'twig.safe_functions',
'read_file',
];
$string =…
- Record
GHSA-662m-56v4-3r8f- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-1336, CWE-94
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
getgrav/gravPackagist |
before 1.8.0-beta.27 | 1.8.0-beta.27 |
getgrav/gravPackagist |
before 1.8.0-beta.27, plus listed versions 0.8.00.9.00.9.10.9.100.9.11 Show 45 moreShow less0.9.120.9.130.9.140.9.150.9.160.9.170.9.180.9.190.9.20.9.200.9.210.9.220.9.230.9.240.9.250.9.260.9.270.9.280.9.290.9.30.9.300.9.310.9.320.9.330.9.340.9.350.9.360.9.370.9.380.9.390.9.40.9.400.9.410.9.420.9.430.9.440.9.450.9.50.9.60.9.70.9.80.9.91.0.01.0.0-rc.11.0.0-rc.2 |
1.8.0-beta.27 |
Public exploits
Links only. Every CVE stores no exploit code.
| Source | Link | Date |
|---|---|---|
| Metasploit | Grav CMS Twig SSTI Authenticated Sandbox Bypass RCE | 2025-12-01 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, Metasploit, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2025-66294 is a high vulnerability (CVSS 8.7) in Getgrav Grav, published December 1, 2025. Public exploit code exists. EPSS puts the chance of exploitation in the next 30 days at 3.02%, the 87th percentile. Fixed in getgrav/grav 1.8.0-beta.27.
References
github.com/getgrav/grav/security/advisories/GHSA-662m-56v4-3r8f
github.com/getgrav/grav/commit/e37259527d9c1deb6200f8967197a9fa587c6458
nvd.nist.gov/vuln/detail/CVE-2025-66294
github.com/advisories/GHSA-662m-56v4-3r8f
github.com/CVEProject/cvelistV5/tree/main/cves/2025/66xxx/CVE-2025-66294.json
github.com/getgrav/grav
Left out here: 267 versions and the rest of 2 source descriptions. The JSON record has them.