Aug 6, 2026·6 min read·2 visits
Craft CMS administrators with template capabilities can read sensitive server files (such as .env and system configurations) by abusing an omission in the dynamic class helper's blocklist to instantiate PHP's SplFileObject.
An information disclosure vulnerability in Craft CMS allows users with administrative or non-sandboxed template-authoring privileges to read arbitrary system and configuration files. The issue stems from an incomplete class instantiation blocklist in the Twig template extension, which omitted PHP's built-in SplFileObject class.
Craft CMS is a content management system built on PHP and the Twig template engine. To facilitate dynamic operations, the platform implements custom Twig extensions that expose utility helper functions directly inside template environments. One such helper is the create() function, designed to allow template authors to instantiate arbitrary utility classes within the Twig environment.
While this feature is intended to increase template flexibility, it introduces a significant attack surface by exposing direct object instantiation capabilities to template authors. To prevent abuse, such as remote command execution or file system manipulation, the helper relies on an explicit blocklist of forbidden classes. However, if a dangerous class is omitted from this blocklist, any user capable of writing or modifying non-sandboxed templates can instantiate that class and interact with its methods.
This specific vulnerability is classified under CWE-470 (Use of Externally-Controlled Input to Select Classes or Code, or 'Unsafe Reflection'). Because the class dynamic creation mechanism did not fully restrict access to file-handling classes, it allowed authenticated users with template-authoring permissions to read arbitrary local files, including confidential configuration keys, via standard PHP object manipulation interfaces.
The underlying vulnerability is located within the createFunction() method inside the custom Twig extension class (src/web/twig/Extension.php). This method accepts a class name identifier as a string and an optional array of parameters, which are then used to dynamically instantiate the specified object using reflection or standard PHP instantiation routines.
To restrict the instantiation of dangerous classes, the method utilizes a blocklist array containing classes known to pose security risks. The original implementation of this blocklist included Symfony\Component\Process\Process (to prevent command injection), GuzzleHttp\Psr7\FnStream (to prevent stream abuse), and SimpleXMLElement (to prevent XML External Entity injection). However, it failed to block SplFileObject, which is a built-in PHP class representing a local file stream.
Because SplFileObject implements PHP's SeekableIterator, RecursiveIterator, and IteratorAggregate interfaces, it behaves as an iterable collection of file lines. When an attacker passes SplFileObject as the target class to the create() helper, the PHP interpreter instantiates the object and opens a read stream to the file path provided in the parameters. This allows the template engine to bypass standard path restrictions and access files directly on the host system.
The vulnerability was mitigated by adding SplFileObject directly to the class blocklist within src/web/twig/Extension.php across both the 4.x and 5.x maintenance branches. This prevents the dynamic instantiation helper from processing any request to create an instance of this file-handling class.
Below is the code-level change applied in the 5.x branch to restrict the instantiation of SplFileObject:
File: src/web/twig/Extension.php
@@ -73,6 +73,7 @@
use IteratorAggregate;
use Money\Money;
use SimpleXMLElement;
+use SplFileObject;
use Symfony\Component\Process\Process;
use Throwable;
use Traversable;
@@ -1552,6 +1553,7 @@ public function createFunction(string|array $type, array $params = []): object
FnStream::class,
Process::class,
SimpleXMLElement::class,
+ SplFileObject::class,
];
foreach ($blocklist as $c) {While this change successfully blocks SplFileObject, a blocklist-based approach remains structurally fragile compared to an allowlist. Third-party packages loaded via Composer into the vendor/ directory could introduce other classes that permit arbitrary file reading, server-side request forgery (SSRF), or deserialization. A robust remediation strategy would deprecate arbitrary dynamic class instantiation in template contexts entirely, or enforce a strict, closed allowlist of permitted utility classes.
To exploit this vulnerability, an attacker must first obtain credentials for an account with permissions to author or edit Twig templates that are evaluated in a non-sandboxed context. This access is typically restricted to administrators or highly privileged content managers who configure system templates, custom fields, or entry-type rendering options within the Craft CMS Control Panel.
Once the template-authoring interface is accessible, the attacker can inject a payload that leverages the create() helper. By specifying the string 'SplFileObject' as the first argument and an array containing the path to a sensitive local file as the second argument, the attacker forces the server to open the target file. The attacker then uses a standard Twig iteration loop ({% for %}) to read each line sequentially and render it to the output page.
The following Twig code snippet demonstrates a functional proof-of-concept payload designed to extract the database configurations and system security keys contained in the local environment file:
{# Craft CMS SplFileObject Arbitrary File Read PoC #}
{% set file = create('SplFileObject', ['.env']) %}
{% for line in file %}
{{ line }}
{% endfor %}The concrete security impact of this vulnerability is significant, as it permits unauthorized access to the application's environment configuration file (.env). The .env file in Craft CMS contains the primary database credentials, third-party API integration keys, SMTP server credentials, and the global application security key (CRAFT_SECURITY_KEY).
Acquiring the CRAFT_SECURITY_KEY represents a high-severity threat. The application uses this key to sign cookies, generate secure tokens, and encrypt serialized data. If an attacker recovers this key, they can craft valid cryptographic signatures to perform object deserialization attacks or forge administrative sessions, potentially escalating the initial information disclosure vulnerability into a remote code execution vector.
Additionally, on host operating systems where PHP file permissions are weak, this vulnerability can be leveraged to read sensitive system configuration files outside the web directory. For example, on standard Linux installations, an attacker could read /etc/passwd to enumerate local system users and facilitate targeted privilege escalation attacks.
The primary remediation for this vulnerability is to upgrade Craft CMS to a patched release. Organizations running the 4.x release line must update to version 4.18.2 or later. Organizations running the 5.x release line must update to version 5.10.6 or later. These updates modify the createFunction() blocklist to prevent the instantiation of SplFileObject and other related file system stream classes.
If patching cannot be executed immediately, administrators should implement defensive configuration controls. Restricting the PHP execution environment using the open_basedir directive in php.ini can limit the directories that PHP's file system classes are permitted to open. This prevents SplFileObject from accessing files outside of designated application paths, even if the blocklist bypass is exploited.
Furthermore, administrative template-authoring capabilities should be strictly restricted to trusted staff members. Organizations should regularly review user permissions to ensure that only authorized developers are granted access to write or modify custom Twig templates, thereby reducing the exposure of non-sandboxed template evaluation interfaces.
| Product | Affected Versions | Fixed Version |
|---|---|---|
Craft CMS CraftCMS | >= 4.0.0, < 4.18.2 | 4.18.2 |
Craft CMS CraftCMS | >= 5.0.0, < 5.10.6 | 5.10.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-470 |
| Attack Vector | Network / Authenticated Administrative User |
| Vulnerability Class | Unsafe Reflection |
| CVSS Score | 4.9 |
| Exploit Status | poc |
| KEV Status | not listed |
The application uses externally-controlled input to select a class or code to instantiate, without sufficiently restricting which classes can be instantiated.
A protocol-parsing vulnerability in the pure-Python HTTP/2 library 'h2' (versions <= 4.4.0) allows unauthenticated remote attackers to perform HTTP Request Smuggling (CWE-444). The vulnerability exists because the library does not validate the uniqueness of 'Host' headers in incoming HTTP/2 request streams. When an upstream gateway parses such requests and downgrades them to HTTP/1.1 for internal backend servers, the resulting stream contains duplicate Host headers, which leads to parsing inconsistency and potential bypass of security filters.
An authorization bypass vulnerability in Craft CMS allows authenticated control panel users with low privileges to reorder global sets. This alters structure and writes to the project configuration database schema without administrative rights.
Prior to versions 10.9.8 and 11.16.1, Mermaid is vulnerable to prototype pollution via its deep-merge utility function assignWithDepth. This helper is invoked by public configuration-setting interfaces, specifically mermaid.initialize, mermaidAPI.setConfig, and mermaidAPI.updateSiteConfig. Because assignWithDepth recursively merges developer-provided properties into Mermaid's internal configuration state without proper sanitization, an attacker who can control or influence the configuration payload can corrupt the global Object.prototype. This vulnerability can lead to security bypasses, cross-site scripting (XSS), or execution flow modifications in applications using vulnerable Mermaid integrations.
A high-severity path traversal vulnerability exists in Traefik's Kubernetes Ingress NGINX provider. The flaw resides in the RewriteTarget middleware, which is auto-generated when an Ingress resource specifies the `nginx.ingress.kubernetes.io/rewrite-target` annotation. This allows remote, unauthenticated attackers to bypass route-level authentication and access restricted downstream endpoints by exploiting a parser differential.
CVE-2026-65600 is a path traversal vulnerability in the ReplacePathRegex middleware component of Traefik. An unauthenticated remote attacker can exploit the vulnerability to inject directory traversal sequences. When Traefik forwards the resulting un-normalized path, downstream backend web servers normalize the request to execute administrative or protected paths, bypassing gateway-enforced security policies.
A critical authentication bypass and context spoofing vulnerability exists in Traefik's BasicAuth, DigestAuth, and ForwardAuth middlewares prior to versions 2.11.51, 3.6.22, and 3.7.6. The flaw arises because Traefik's header cleanup mechanisms rely on Go's standard library header canonicalization, which does not modify or delete headers containing underscores. Consequently, unauthenticated remote attackers can inject custom underscore-variant headers (e.g., X_Auth_User) that bypass Traefik's stripping filters and reach backend application servers. When downstream backends normalize both hyphens and underscores into the same environment variables, the attacker's spoofed identity value is processed as trusted authorization data.