Sep 23, 2026·6 min read·17 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-16454 is an object-level authorization bypass vulnerability (CWE-284, CWE-862) in Eclipse hawkBit versions 1.0.3 and prior. The flaw exists within the Direct Device Integration (DDI) REST controller (hawkbit-ddi-resource), where endpoints responsible for enumerating software module metadata and serving firmware binaries fail to verify whether the requested software module is assigned to the authenticated device. Consequently, any device with valid credentials (such as a TargetToken or GatewayToken) can enumerate software module identifiers and download arbitrary firmware artifacts across the entire tenant namespace.
CVE-2026-62284 (GHSA-5w5g-j6hw-6p8f) is a code injection and server-side request forgery vulnerability in the console-proxy component of the OSAC Operator. The RemoteConfigResolver parses Kubernetes Secrets containing kubeconfig files via clientcmd.RESTConfigFromKubeConfig without sanitizing execution-related fields. An attacker with RBAC permissions to create or modify labeled Secrets in monitored namespaces can supply a malicious exec credential plugin, resulting in arbitrary command execution within the console-proxy pod.
CVE-2026-62361 (GHSA-xgjr-7j9q-2h4r) is an authenticated SQL injection and authorization bypass vulnerability in listmonk, an open-source, self-hosted newsletter and mailing list manager written in Go. In versions prior to 6.2.0, the subscriber export endpoint (GET /api/subscribers/export) directly interpolates user-supplied SQL filter expressions into a PostgreSQL query without invoking the table allowlist validation function (validateQueryTables). Consequently, authenticated users possessing the subscribers:sql_query and subscribers:get_all permissions can bypass relational access controls, execute arbitrary subqueries against restricted tables such as users and settings, and modify database state via writable Common Table Expressions (CTEs).
CVE-2026-28385 (GHSA-3gq2-x4qg-p4g6) is a Server-Side Request Forgery (SSRF) vulnerability in Canonical LXD versions 4.12 through 6.9. An authenticated user possessing the can_create_images entitlement can force the LXD daemon to execute arbitrary outbound HTTP and HTTPS requests via the /1.0/images API endpoint. Due to the absence of egress destination validation, an attacker can probe host loopback services, RFC 1918 private network segments, and cloud Instance Metadata Services (IMDS) from the network position of the privileged LXD daemon.
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.
CVE-2026-48749 (tracked as GHSA-vghh-5rfx-xhq8 for LXD and GHSA-2q3f-q5pq-g8wv for Incus) is a critical container escape vulnerability in the Canonical LXD and Linux Containers Incus system container managers. By importing a specially crafted container image archive containing duplicate tar member headers, an authenticated attacker can replace the instance rootfs directory with a symbolic link pointing to the underlying host root filesystem. When performing file operations on a stopped container, the privileged forkfile helper binary resolves the symbolic link without confinement and chroots directly into the host filesystem, granting arbitrary root-level file read and write access.