T09 · Insecure Skill Coding Practices
- Location
- scripts/worker.js:38
- Finding
- Authentication Fails Open When G2_TOKEN Is Not Configured## Vulnerability Details **File Location**: `scripts/worker.js:38-41` **Vulnerability Type**: Fail-open authentication **Risk Level**: High ### Vulnerable Code ```js // Auth: G2 → Worker if (env.G2_TOKEN) { const auth = request.headers.get('Authorization'); if (auth !== `Bearer ${env.G2_TOKEN}`) return json({ error: 'Unauthorized' }, 401); } ``` ### Technical Analysis The Worker verifies the caller's bearer token only when `env.G2_TOKEN` is defined. If the secret is absent because of a deployment or configuration error, the authentication block is skipped and all POST requests are accepted without credentials. Although `G2_TOKEN` is documented as required, the implementation does not enforce that requirement. This creates a fail-open access-control boundary on a publicly reachable Cloudflare Worker. An unauthenticated caller can submit arbitrary OpenAI-compatible messages that the Worker forwards using its own privileged Gateway and third-party API credentials. The exposed operations include: - Sending arbitrary prompts to the OpenClaw Gateway with `GATEWAY_TOKEN`. - Invoking tools and capabilities available to the configured `main` agent. - Triggering the Anthropic fallback when the Gateway request fails. - Triggering OpenAI image generation through matching prompts. - Causing long-task results, supplied prompts, generated-image references, or errors to be delivered to the configured Telegram chat. The Telegram network behavior is otherwise consistent with the declared optional rich-content delivery feature. The primary vulnerability is that an omitted authentication secret allows unauthorized users to trigger it. ### Attack Path 1. The operator deploys the Worker but accidentally omits the `G2_TOKEN` Cloudflare secret. 2. The public `workers.dev` URL is discovered through enumeration, logs, documentation, or ordinary exposure. 3. An attacker sends a POST request containing an OpenAI Chat Completions-style message without an `Authorization` hea ...[truncated 1501 chars]
- Remediation
- ## Remediation Suggestions Enforce authentication unconditionally and fail closed if the required secret is absent: ```js if (!env.G2_TOKEN) { return json({ error: 'Service not configured' }, 503); } const auth = request.headers.get('Authorization'); if (auth !== `Bearer ${env.G2_TOKEN}`) { return json({ error: 'Unauthorized' }, 401); } ``` Apply additional defense-in-depth controls: 1. Validate required secrets during deployment and include a deployment smoke test that confirms unauthenticated POST requests receive `401` or `503`. 2. Add per-client and global rate limits to reduce API-credit abuse and denial-of-service risk. 3. Enforce a maximum request-body size and maximum message length before parsing or forwarding input. 4. Restrict the Gateway token and the `main` agent to the minimum tools and permissions required by the glasses bridge. 5. Consider using a dedicated, least-privileged Gateway agent rather than the general-purpose `main` agent. 6. Add explicit authorization controls for expensive image-generation and long-running task routes. 7. Monitor repeated authentication failures, long-task invocation volume, and abnormal third-party API usage. 8. Rotate `G2_TOKEN` immediately if the glasses or configured endpoint details are exposed.
