T09 · Insecure Skill Coding Practices
Error
- Location
- dashboard/server.py:420
- Finding
- Dashboard Action Token Disclosed to Unauthenticated Page Requesters<![CDATA[ ## Vulnerability Details **File Location**: `dashboard/server.py:420-423` **Vulnerability Type**: Authentication secret disclosure and action authorization bypass **Risk Level**: High ### Vulnerable Code ```python def send_static(self, path: Path, content_type: str) -> None: if not path.exists(): self.send_error(HTTPStatus.NOT_FOUND) return body = path.read_bytes() if path.name == "index.html": injection = f"<script>window.WATCHDOG_ACTION_TOKEN = {json.dumps(ACTION_TOKEN if ACTIONS_ENABLED else '')};</script>" body = body.replace(b"</head>", injection.encode("utf-8") + b"</head>") self.send_response(200) self.send_header("Content-Type", content_type) self.send_header("Cache-Control", "no-store") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) ``` The token protects the following sensitive actions: ```python def verify_action(headers) -> tuple[bool, str]: if not ACTIONS_ENABLED: return False, "Dashboard actions are disabled." token = headers.get("X-Watchdog-Token", "") if not ACTION_TOKEN or not secrets.compare_digest(token, ACTION_TOKEN): return False, "Invalid or missing dashboard action token." return True, "ok" ``` ### Technical Analysis The dashboard's supposedly secret action token is embedded directly into every unauthenticated response for `/` or `/index.html`. Consequently, any client capable of requesting the dashboard page can recover the credential from `window.WATCHDOG_ACTION_TOKEN`. The server does not validate the HTTP `Host` or `Origin` header. Binding to `127.0.0.1` reduces direct remote exposure but does not establish an authentication boundary. Local malware, another process running under the user, a browser extension, or a browser-based DNS-rebinding attack could potentially request the page and obtain the token. Once recovered, the token authorizes Gateway restart, diagnostics exec ...[truncated 1283 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Never embed `ACTION_TOKEN` in HTML or JavaScript. 2. Keep dashboard actions disabled by default unless the user explicitly enables them. 3. Require the user to enter the token manually or establish an authenticated session. 4. If session authentication is used, store the session identifier in a cookie with: - `HttpOnly` - `SameSite=Strict` - An appropriate `Secure` policy where HTTPS is available 5. Validate `Host` against an allowlist such as `127.0.0.1:18790` and `localhost:18790`. 6. Reject state-changing requests whose `Origin` does not match the dashboard origin. 7. Consider requiring a fresh confirmation or short-lived nonce for Gateway restarts. 8. Rate-limit failed authentication and sensitive action requests. 9. Do not store the action token in browser `localStorage`, because any script executing in the dashboard origin can retrieve it. ]]>
