T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- src/modules/developer-agent.ts:28
- Finding
- Read-Only Skill Exposes Account Credential Management Operations<![CDATA[ ## Vulnerability Details **File Location**: `src/modules/developer-agent.ts:28-56` **Related Locations**: `SKILL.md:3,13-20`; `src/index.ts:94,128` **Vulnerability Type**: Least-privilege violation through account credential management **Risk Level**: High ### Technical Analysis The Skill declares itself to be a read-only, data-retrieval-only SDK: ```markdown description: Financial data SDK for AI Agents. 218+ read-only endpoints for market data, prices, fundamentals. Built for Cursor, Claude, OpenClaw. Data retrieval only. ``` It further states: ```markdown - **Read-only API** — fetches public market data only - **No wallet access** — does not interact with wallets or private keys - **No trading execution** — execute modules are for quote simulation only, not live trades - **Data only** — returns JSON market data for analysis ``` However, the publicly exported `DeveloperModule` provides authenticated account credential creation, rotation, verification, and purported revocation: ```ts /** Create a new API key */ async createKey(params: { name: string; description?: string; tier?: string; expires_in_days?: number; }): Promise<{ key: string; key_id: string; [k: string]: unknown }> { return this.c.post('/auth/keys', params); } /** List your API keys */ async listKeys(include_revoked = false): Promise<unknown[]> { return this.c.get('/auth/my/keys', { params: { include_revoked } }); } /** Revoke an API key */ async revokeKey(keyId: string): Promise<void> { // DELETE — use post trick with method override, or add delete to client if needed await this.c.get(`/auth/my/keys/${encodeURIComponent(keyId)}`); } /** Rotate an API key (get a new secret) */ async rotateKey(keyId: string): Promise<{ key: string; [k: string]: unknown }> { return this.c.post(`/auth/my/keys/${encodeURIComponent(keyId)}/rotate`, {}); } /** Verify an API key is valid */ async verifyKey(key: string): Promise<{ valid: boolean; tier?: string; [k: string]: unknow ...[truncated 1818 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove credential-management operations from the read-only SDK. 2. Move `createKey`, `rotateKey`, `revokeKey`, and `verifyKey` into a separately distributed administrative package. 3. Require a distinct administrative credential or OAuth scope that is not accepted by market-data endpoints. 4. Do not instantiate or export administrative modules by default. 5. Require explicit user confirmation immediately before any credential mutation. 6. Redact returned secrets from logs, telemetry, error messages, and agent transcripts. 7. Return newly created secrets only through a dedicated secure-secret interface. 8. Update `SKILL.md` and user documentation to accurately disclose any retained account-management capabilities. 9. Add authorization tests proving that ordinary read-only keys cannot invoke credential-management endpoints. ]]>
