T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/prepare_data.mjs:23
- Finding
- Environment-Controlled API Destination Can Receive the SentiSense API Key## Vulnerability Details **File Location**: `scripts/prepare_data.mjs`, lines 23 and 73–77 **Vulnerability Type**: Credential disclosure through an insufficiently restricted network destination **Risk Level**: High ### Vulnerable Code ```js const BASE = process.env.SENTISENSE_BASE_URL || "https://app.sentisense.ai"; const KEY = process.env.SENTISENSE_API_KEY; ``` ```js response = await fetch(`${BASE}${path}`, { headers: { "X-SentiSense-API-Key": KEY, Accept: "application/json", "User-Agent": UA }, }); ``` ### Technical Analysis The script allows `SENTISENSE_BASE_URL` to override the API origin. Every request to that origin unconditionally includes the secret `SENTISENSE_API_KEY` in the `X-SentiSense-API-Key` header. The override is not validated to require HTTPS or restrict the hostname to `app.sentisense.ai`. Consequently, a process environment controlled or influenced by another component can redirect the credential to an arbitrary HTTP or HTTPS server. The declared functionality requires only the official SentiSense API, so forwarding the credential to an unrestricted destination exceeds the minimum network privileges necessary. An attacker-controlled endpoint can also return fabricated quote, volatility, and earnings responses. Those values may be incorporated into the generated payoff artifact, creating an integrity risk in addition to credential disclosure. ### Attack Path 1. An attacker or compromised launcher influences the environment used to execute the Skill. 2. The attacker sets `SENTISENSE_BASE_URL` to an endpoint they control, such as `https://attacker.example`. 3. The user invokes the documented command with a valid `SENTISENSE_API_KEY`. 4. `prepare_data.mjs` constructs requests using the attacker-controlled base URL. 5. The script sends the API key to that server in the `X-SentiSense-API-Key` header. 6. The attacker records the credential and can return structurally valid but manipulated ...[truncated 678 chars]
- Remediation
- ## Remediation Suggestions - Remove `SENTISENSE_BASE_URL` support if alternate servers are not required. - Otherwise, parse the configured destination with `new URL()` and enforce: - `protocol === "https:"` - `hostname === "app.sentisense.ai"` - the expected port and base pathname - no embedded username or password - Construct request URLs relative to a fixed, trusted origin rather than concatenating strings. - Attach the API-key header only after confirming that the final URL uses the approved origin. - Reject redirects to unapproved origins, or use `redirect: "manual"` and validate every redirect target before following it with credentials. - Add automated tests proving that HTTP destinations, lookalike domains, user-info tricks, alternate ports, and cross-origin redirects cannot receive the key. - Document any legitimate custom-server feature explicitly and require a separate, scoped credential for it.
