T09 · Insecure Skill Coding Practices
- Location
scripts/status_server.py:100- Finding
Unauthenticated Network Exposure of Agent Activity Metadata
- Content
View full analysis
Vulnerability Details
File Location:
scripts/status_server.py:100-112
Supporting Locations:scripts/status_server.py:16-17,SKILL.md:156-163
Vulnerability Type: Unauthenticated information exposure caused by an overly broad network binding and permissive CORS policy
Risk Level: MediumVulnerable Code
python def do_GET(self): if self.path == "/status" or self.path == "/": status = get_openclaw_status() self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() self.wfile.write(json.dumps(status, indent=2).encode()) else: self.send_response(404) self.end_headers() def main(): port = int(os.environ.get("PORT", 8765)) server = HTTPServer(("0.0.0.0", port), StatusHandler)The exposed information is derived from OpenClaw session metadata:
python workspace = Path.home() / ".openclaw" sessions_dir = workspace / "agents" / "main" / "sessions"The documentation additionally recommends allowing network access to the service:
bash sudo ufw allow 8765/tcpTechnical Analysis
The HTTP service binds to
0.0.0.0, making it reachable through every available network interface rather than only the loopback interface. Neither/nor/statusperforms authentication or authorization before returning status information.The response includes agent state, activity timestamps, active sub-agent task counts, and descriptive activity text. Although the implementation only examines session filenames and modification times and does not read session contents, the resulting metadata can disclose when a user or agent is active, idle, or processing concurrent tasks.
The
Access-Control-Allow-Origin: *response header also permits scripts hosted by arbitrary web o ...[truncated 2160 chars]- Remediation
View remediation
Remediation Suggestions
-
Bind to loopback by default:
python bind_address = os.environ.get("BIND_ADDRESS", "127.0.0.1") server = HTTPServer((bind_address, port), StatusHandler) -
Require an explicit configuration change before allowing LAN access, and clearly warn users that binding to
0.0.0.0exposes activity metadata to reachable clients. -
Add authentication for non-loopback deployments. For example, require a sufficiently random API token in an
Authorization: Bearerheader and compare it using a constant-time comparison function. -
Replace the wildcard CORS policy with either no CORS header or an allowlist containing only the intended dashboard origin. Do not treat CORS as a substitute for authentication.
-
Restrict firewall rules to the specific trusted device or private subnet instead of allowing all sources. For example:
bash sudo ufw allow from TRUSTED_DEVICE_IP to any port 8765 proto tcp -
Place the service behind an authenticated reverse proxy with TLS if it must be accessed outside a trusted private network. Do not expose the plaintext API directly to the internet.
-
Minimize response data by omitting exact timestamps, personalized text, and task counts unless they are required by the display.
-
Avoid returning raw exception strings in API responses, as they may disclose local paths or implementation details. Log detailed errors locally and return a generic status message to clients.
-
