Sep 23, 2026·6 min read·5 visits
Unauthenticated remote attackers can inject Twig expressions into form inputs in Solspace Freeform versions 5.x < 5.10.14. When validation fails and the form re-renders, the input values are processed by an isolated Twig instance, allowing system configuration and path disclosure.
A technical analysis of CVE-2026-73858 / GHSA-gxrg-x694-283w, a server-side template injection vulnerability in the Solspace Freeform plugin for Craft CMS. The vulnerability permits unauthenticated users to trigger dynamic Twig evaluation of input fields during form validation re-rendering, causing local directory path disclosure and PHP runtime information exposure.
Solspace Freeform is an enterprise-grade form builder plugin designed for Craft CMS. It allows administrators to build, manage, and render complex multi-step forms directly inside the Craft CMS control panel. To handle diverse presentation layers, Freeform utilizes a dynamic serialization engine to parse field configuration data and output raw HTML attributes.
This dynamic serialization process creates a public-facing attack surface. When a client interacts with a form, submitted parameters are often maintained across requests to support multi-page forms or preserve inputs when validation rules are not met. If the system does not cleanly separate user-supplied input state from system-defined template parameters, the input can be executed within a trusted rendering context.
This vulnerability is classified under CWE-1336 (Improper Neutralization of Special Elements Used in a Template Engine). Unauthenticated remote attackers can execute arbitrary Twig template expressions within an isolated renderer. The resulting output is subsequently reflected back to the client inside the target input element's HTML markup.
The vulnerability resides in how Freeform serializes HTML attributes for form components. Specifically, the class Solspace\Freeform\Library\Attributes\Attributes handles the preparation of attributes before formatting them as HTML strings. This formatting is initiated through the toHtmlTagArray(?array $properties = null) method.
To support administrative overrides and dynamic rendering (such as evaluating control panel macros or dynamic placeholders), the plugin routes attribute values through an instance of the Twig renderer. In versions prior to 5.10.14, this processing did not check if the attribute key held user-supplied POST data versus statically configured server-side variables.
When a validation failure occurs during a form submission, the previously submitted user input is populated into the field array as the value attribute to allow re-entry. When the form re-renders to present validation errors, toHtmlTagArray() executes. The loop processes the value key, blindly passing the user-submitted string containing malicious Twig syntax into the $twig->render() execution context, triggering immediate template parsing.
Prior to the patch, the loop in Attributes.php executed $twig->render($value, $properties) on any non-empty value, regardless of whether the key represented a static configuration attribute or a dynamic user input. Below is the vulnerable segment:
// Vulnerable code in Attributes.php
public function toHtmlTagArray(?array $properties = null): array
{
// ...
$replacements = [];
foreach ($array as $key => $value) {
$key = $twig->render($key, $properties);
$value = !empty($value) ? $twig->render($value, $properties) : $value;
$replacements[$key] = $value;
}
// ...
}The mitigation introduced in commit 5f7555320635f1cd3b4c478aa0b58e8c3144313b adds a restricted array of attributes to prevent evaluation:
private const EXCLUDED_TWIG_ATTRIBUTES = ['value', 'name', 'id'];The loop was modified to prevent Twig rendering if the key is present in this denylist:
if (!empty($value) && !\in_array($key, self::EXCLUDED_TWIG_ATTRIBUTES, true)) {
$value = $twig->render($value, $properties);
}This mitigation relies on a denylist model. If an attacker can inject values that serialize into other HTML attributes (such as data-*, title, or placeholder) that are not explicitly defined in EXCLUDED_TWIG_ATTRIBUTES, those values will still be parsed by the template engine. A structural and secure remediation would utilize an allowlist or completely avoid processing attributes using the template engine when they contain user-supplied HTTP request context.
To exploit the vulnerability, an attacker must identify a public-facing Freeform form. The exploitation vector requires submitting the form with an intentional validation error (e.g., omitting a required field or providing an invalid email format) while injecting a Twig expression into a text-based or email-based input field.
A typical payload targeting environment variables takes the form of {{ constant('CRAFT_VENDOR_PATH') }}. When the server processes the validation failure, it preserves the payload to prepopulate the field for the user. During the rendering cycle, the Twig expression is evaluated. The server returns the final HTML response containing the evaluated variable within the input field's markup:
<input type="text" name="fields[first_name]" value="/var/www/vhosts/site/vendor/" />This workflow is illustrated below:
The security impact of CVE-2026-73858 is scoped to local information disclosure. Due to the sandboxed nature of the specific Twig context instantiated by Freeform, the template engine is restricted. The rendering class blocks the instantiation of core Craft CMS system components such as craft.app or access to underlying environment configuration variables (.env files) and native PHP functions like system or exec.
Despite these restrictions, an attacker can extract system properties via PHP constants. Using the constant() function, attackers can retrieve system-level variables including the exact PHP version (PHP_VERSION), the server host operating system (PHP_OS), and critical server directory layouts (CRAFT_BASE_PATH and CRAFT_VENDOR_PATH).
These disclosures degrade the defense-in-depth posture of the host environment. Knowing the exact filesystem paths and PHP runtime environments allows malicious actors to customize subsequent attacks or match identified software combinations against known local file inclusion (LFI) or remote code execution (RCE) vectors.
Remediation of this vulnerability requires upgrading Freeform to version 5.10.14 or later. In environments where an immediate upgrade is not possible, security teams should implement defensive patterns. Modifying public template configurations to sanitize user input prior to output rendering can temporarily mitigate the vector.
Web Application Firewalls (WAFs) can detect exploitation attempts by evaluating incoming POST bodies for Twig block syntax containing standard functions or constants. Signature analysis should identify double-curly brackets accompanied by keywords such as constant, CRAFT_, or PHP_ within the context of form input fields.
Below is a standard Snort detection signature designed to detect potential template injection attempts directed at Freeform instances:
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"COTS Exploit Solspace Freeform SSTI Attempt"; flow:established,to_server; content:"POST"; http_method; content:"fields["; http_client_body; content:"{{"; http_client_body; content:"constant("; http_client_body; content:"}}"; http_client_body; reference:cve,2026-73858; classtype:web-application-attack; sid:1000001; rev:1;)CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Solspace Freeform Solspace | >= 5.0.0, < 5.10.14 | 5.10.14 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1336 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.3 (Medium) |
| Exploit Status | Proof-of-Concept (PoC) |
| CISA KEV Status | Not Listed |
| Impact | Information Disclosure / Local Path Leakage |
The application accepts user input and embeds it directly inside a template structure before rendering, permitting template injection.
CVE-2026-88974 is an incorrect authorization vulnerability in the WPGraphQL plugin for WordPress. Due to a failure to perform object-level capability checks or validate status-transition requirements in the updatePost mutation handler, authenticated Contributor-level users can publish their own draft posts without editorial approval or modify their previously published posts.
An algorithmic complexity vulnerability (CWE-407) in the query decoder of the Elixir Plug library (CVE-2026-54892) allows unauthenticated remote attackers to trigger scheduler starvation and denial of service by transmitting deeply nested brackets in query parameters or URL-encoded post bodies.
CVE-2026-83801 is a stored Cross-Site Scripting (XSS) vulnerability in Nautobot. The vulnerability arises because the application interpolates user-controlled database properties—specifically Relationship descriptions and Module Family names—directly into the help_text parameter of Django form fields. These fields are rendered using Django's |safe filter, bypassing HTML escaping and enabling persistent injection. When an administrative user accesses the affected forms, the payload executes contextually in their browser. This allows attackers to hijack active sessions and perform unauthorized operations. Nautobot versions prior to v2.4.37 and v3.1.8 are affected by this vulnerability. The issue has been patched by implementing contextual HTML escaping and strict markdown sanitization.
An authorization bypass vulnerability exists in Nautobot's REST API endpoints handling approval workflows. Due to an architectural inconsistency, a standalone, generic REST API endpoint for creating approval responses was exposed without propagating the required business-logic validations. This allows low-privileged authenticated users to submit forged, self-approved votes, bypassing approval thresholds and triggering unauthorized server-side automated jobs.
CVE-2026-85709 is a sensitive information exposure vulnerability in HKUDS LightRAG prior to version 1.5.5. The vulnerability allows remote, unauthenticated clients to trigger server-side errors and receive raw Python exception details, including local filesystem paths, database connection strings, credentials, and internal system configurations.
HKUDS LightRAG prior to version 1.5.5 is vulnerable to multiple timing side-channels (CWE-208) in its API authentication layer. The password verification logic in `lightrag/api/passwords.py` compares plaintext administrative credentials using Python's short-circuiting equality operator (`==`). Additionally, `lightrag/api/auth.py` terminates authentication early on non-existent usernames, creating an observable latency difference compared to computationally expensive bcrypt comparisons on valid accounts. Together, these allow remote unauthenticated attackers with low-latency network access to enumerate valid usernames and extract plaintext passwords character by character.