T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/pocket-lens.mjs:21
- Finding
- Arbitrary API Endpoint Can Receive Bearer Credentials and Financial Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pocket-lens.mjs:21-24, 35-40, 61-71` **Vulnerability Type**: Unrestricted sensitive-data transmission endpoint **Risk Level**: High ### Vulnerable Code ```js const API_KEY = process.env.POCKET_LENS_API_KEY; const API_URL = (process.env.POCKET_LENS_API_URL || "https://pocketlens.app").replace( /\/$/, "" ); function headers() { return { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json", Accept: "application/json", }; } async function request(method, path, body) { const url = `${API_URL}${path}`; const opts = { method, headers: headers() }; if (body !== undefined) { opts.body = typeof body === "string" ? body : JSON.stringify(body); } let res; try { res = await fetch(url, opts); } catch (err) { exitWithError(`Network error: ${err.message}`); } ``` The custom endpoint is also explicitly documented in `SKILL.md:33-36`: ```md - `POCKET_LENS_API_URL` (optional): Base URL for the PocketLens API. Defaults to `https://pocketlens.app` if not set. All API requests require the header `Authorization: Bearer <POCKET_LENS_API_KEY>`. ``` ### Technical Analysis `POCKET_LENS_API_URL` is trusted without validating its scheme, hostname, port, path, or ownership. The script subsequently attaches the PocketLens bearer credential to every request made through this endpoint. When creating a transaction, the request body can contain sensitive personal financial information, including merchant names, transaction amounts, timestamps, card issuer names, categories, and descriptions. Read operations can also expose account identity, spending summaries, category information, and card billing details. Although network transmission to the default PocketLens service is necessary for the declared functionality, allowing an arbitrary endpoint to receive the production bearer credential and financial records is not necessary for normal operation and exc ...[truncated 1624 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove support for arbitrary API origins unless self-hosting is an explicit product requirement. 2. Allowlist the production origin exactly, for example: - Scheme: `https:` - Hostname: `pocketlens.app` - Expected port only - No embedded username or password 3. Parse custom values with `new URL()` and reject: - Plaintext HTTP. - Unexpected hosts or ports. - Embedded credentials. - Unexpected base paths. - Malformed or non-network schemes. 4. If custom or self-hosted servers must be supported, require an explicit trusted-host allowlist and use a separate credential scoped to that server. Never reuse the production PocketLens credential automatically. 5. Bind credentials to an expected audience or origin on the server side where possible. 6. Recommend only the minimum API permission required for each operation. Do not recommend `full` access where `write` or read-only credentials are sufficient. 7. Warn users that changing the endpoint changes the party receiving their credential and financial records. 8. Consider splitting read and write operations across separate least-privilege credentials. ]]>
