Aug 7, 2026·5 min read·12 visits
Authenticated users can exfiltrate sensitive environment variables by abusing sequential evaluation of environment parsing and sandboxed Twig templates.
An authenticated information disclosure vulnerability in Craft CMS allows high-privilege administrators to extract sensitive environment variables, including the CRAFT_SECURITY_KEY and database credentials, using a blind error-based template injection attack within element select condition rules.
In Craft CMS, authenticated administrators or users with access to the Control Panel can configure element select condition rules. These rules utilize input parameters such as elementId in Craft 4 or elementIds in Craft 5 to dynamically filter and select specific content assets or entries.
A previous vulnerability fix, CVE-2026-31857 (GHSA-fp5j-j7j4-mcxc), attempted to secure this input channel by enforcing the use of a sandboxed Twig template rendering engine when processing user-defined inputs. This sandbox was designed to prevent remote code execution via Server-Side Template Injection (SSTI).
Despite the sandbox protection, GHSA-596P-6JV8-775V introduces a validation bypass in the template processing pipeline. An authenticated attacker can exploit the sequence in which inputs are resolved to perform a blind error-based injection attack, ultimately exfiltrating sensitive environment variables from the server config.
The root cause of this vulnerability lies in a sequence-of-operations flaw where environment variable interpolation occurs before sandboxed template rendering.
When evaluating the condition rule parameters, the application first passes the input string to the App::parseEnv() helper method. This method automatically processes and interpolates environment variables or secrets matching patterns like $ENV_VAR or ${ENV_VAR}.
Immediately following this environment variable interpolation, the resulting string is rendered as a Twig template via renderSandboxedObjectTemplate(). Because the secrets are inserted directly into the string before rendering, Twig parses the resolved secret values as part of the executable template context rather than as plain, non-evaluable text literals.
Although the Twig engine operates within a restricted sandbox that blocks dangerous PHP functions and classes, an attacker can still write standard control flow statements. By crafting conditional statements that check individual characters of the interpolated environment variables, the attacker can trigger runtime execution exceptions based on whether a specific condition is met.
In vulnerable versions of Craft CMS 4 (pre-4.18.2), the vulnerable flow is located in src/base/conditions/BaseElementSelectConditionRule.php within the getElementId method:
public function getElementId(bool $parse = true): int|string|null
{
if ($parse && is_string($this->_elementId)) {
// Step 1: Interpolate environment variables into the string
$elementId = App::parseEnv($this->_elementId);
if ($this->condition instanceof ElementCondition && isset($this->condition->referenceElement)) {
$referenceElement = $this->condition->referenceElement;
} else {
$referenceElement = new stdClass();
}
// Step 2: Pass the interpolated string to the template engine
return Craft::$app->getView()->renderSandboxedObjectTemplate($elementId, $referenceElement);
}
return $this->_elementId;
}The implementation in Craft CMS 5 (pre-5.10.6) reflects the same logical design flaw inside the modified array handler getElementIds:
public function getElementIds(bool $parse = true): array|string
{
if ($parse && is_string($this->_elementIds)) {
// Step 1: Interpolation occurs first
$elementIds = App::parseEnv($this->_elementIds);
if ($this->condition instanceof ElementCondition && isset($this->condition->referenceElement)) {
$referenceElement = $this->condition->referenceElement;
} else {
$referenceElement = new stdClass();
}
// Step 2: The output of step 1 is compiled
$elementIds = Craft::$app->getView()->renderSandboxedObjectTemplate($elementIds, $referenceElement);
return array_values(array_filter(array_map(
fn(string $elementId) => (int)trim($elementId),
explode(',', $elementIds),
)));
}
return $this->_elementIds;
}The vulnerability is resolved in the updated releases by adding strict regex checks. If environment variable interpolation alters the initial string, additional Twig templating execution is completely bypassed unless the original input is a simple environment variable format matching /^\$\{?\w+\}?$/.
An attacker with Control Panel access can exploit this vulnerability using a blind error-based template injection technique. This requires crafting a payload that dynamically evaluates a character of the target variable and triggers a standard PHP runtime error on a match.
The attacker inputs the following payload into a condition rule text field:
{% if "${CRAFT_SECURITY_KEY}"|slice(0, 1) == "a" %}{{ 1/0 }}{% endif %}When the server processes this rule, App::parseEnv() resolves ${CRAFT_SECURITY_KEY} into its actual plaintext value. The Twig compilation engine then evaluates the comparison expression:
{{ 1/0 }}. This produces a DivisionByZeroError, resulting in an HTTP 500 Internal Server Error returned to the attacker.By programmatically adjusting the slice index and testing different characters, an automated script can reconstruct sensitive keys character-by-character.
A successful exploit allows the exfiltration of core secrets. The main target of such an attack is the CRAFT_SECURITY_KEY, which is responsible for signing cookies, sessions, and security tokens. Gaining access to this key allows attackers to forge administrative sessions, perform object injection, and potentially escalate permissions to remote code execution.
Additionally, secondary variables such as CRAFT_DB_PASSWORD (database credentials), API keys, and SMTP server passwords can be exfiltrated. This introduces risks of lateral movement and complete compromise of external databases or connected cloud environments.
While this attack requires authenticated access with permissions to define element condition rules, it presents a substantial risk in multi-tenant installations, delegated administration frameworks, or instances compromised via minor entry points.
To remediate this vulnerability, administrators must update Craft CMS installations to the patched versions immediately.
The official patch mitigates the flaw by implementing validation checks. The application checks if the environment-resolved string differs from the original. If a change is detected, it only permits rendering if the string contains a single, simple environment variable format without complex syntax structures or Twig delimiters.
If immediate updates are not possible, administrators should restrict Control Panel access to trusted personnel and closely monitor database tables and configuration files for unexpected Twig delimiters inside condition rules.
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Craft CMS Pixel & Tonic | >= 4.0.0-RC1, <= 4.18.1 | 4.18.2 |
Craft CMS Pixel & Tonic | >= 5.0.0-RC1, <= 5.10.5 | 5.10.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1336 |
| Attack Vector | Network |
| CVSS v4.0 | 5.1 |
| Impact | Partial Information Disclosure |
| Exploit Status | Proof-of-Concept |
| Privileges Required | High (Admin Access) |
| CISA KEV Status | No |
Improper Neutralization of Special Elements Used in a Template Engine
A critical vulnerability exists in the praxis-proxy library where the omission of default limits on HTTP/2 server options allows remote attackers to trigger a Denial of Service (DoS) using an HPACK compression bomb and flow-control window stalls. This vulnerability is cataloged as GHSA-cjcg-cxmh-9wcr.
A Use-After-Free (UAF) vulnerability exists in the sqlite3-ruby native C extension when marshaling arguments for user-defined SQLite aggregate functions with multiple arguments. Due to temporary heap-allocated argument arrays not being registered with the Ruby Garbage Collector, active objects can be prematurely reclaimed, resulting in memory corruption or process-level crashes.
An unauthenticated remote denial of service vulnerability exists in @fastify/busboy versions 3.1.0 through 3.2.0. The vulnerability is caused by an integer wrap-around in the Boyer-Moore-Horspool algorithm implementation inside the sbmh submodule when initializing skip distances. When processing a specific boundary of 252 bytes, the parser triggers an infinite loop, stalling the single-threaded Node.js event loop and exhausting CPU resources.
A critical remote, unauthenticated Denial of Service (DoS) vulnerability in @fastify/busboy (<= 3.2.0) allows attackers to crash the Node.js process. By submitting a crafted multipart/form-data request with a header key matching an inherited property of Object.prototype (like __proto__ or constructor), the internal HeaderParser triggers a synchronous TypeError.
SiYuan is an open-source personal knowledge management system. Its Model Context Protocol (MCP) implementation within the asset.upload tool contains a path-traversal and workspace boundary bypass flaw. This allows remote AI models—acting on behalf of attackers via malicious prompts or documents—to import and read sensitive host-system files, such as private keys and system configurations, through absolute path inputs.
An Server-Side Request Forgery (SSRF) vulnerability via DNS-Rebinding Time-of-Check to Time-of-Use (TOCTOU) has been discovered in SiYuan (思源笔记), an open-source personal knowledge management system. The flaw exists within the AI Agent tools http_request (util.HTTPRequest) and web_fetch (util.WebFetch) of the SiYuan Kernel, allowing unauthenticated remote attackers to bypass SSRF validation and access private internal services or cloud metadata endpoints.