T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/launchpulse.cjs:126
- Finding
- Authentication and third-party secrets can be redirected to an arbitrary API endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/launchpulse.cjs`, lines 126-129, 318, 365-368, 717-719, 1458-1477, 2069-2079, and 2160-2184 **Vulnerability Type**: Unrestricted destination for sensitive network requests **Risk Level**: High ### Vulnerable Code ```js function normalizeApiBaseUrl(value) { const fallback = DEFAULT_API_BASE_URL; const raw = value && String(value).trim().length ? String(value).trim() : fallback; return raw.replace(/\/+$/, ''); } ``` ```js let apiBase = process.env.LAUNCHPULSE_API_BASE_URL || DEFAULT_API_BASE_URL; ``` ```js if (a === '--api-base') { apiBase = args[i + 1] || apiBase; i += 1; continue; } ``` ```js function buildAuthHeaders(bearerToken) { return bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {}; } ``` The same configurable backend can receive third-party deployment credentials: ```js const githubUsername = cfg.githubUsername || process.env.GITHUB_USERNAME || null; const githubToken = cfg.githubToken || process.env.GITHUB_TOKEN || null; const flyApiToken = cfg.flyToken || process.env.FLY_API_TOKEN || null; if (!githubUsername || !githubToken || !flyApiToken) { throw new Error('deploy --target fly requires --github-username, --github-token, and --fly-token (or env vars)'); } startResult = await fetchJson( withUserId(`${cfg.apiBase}/project/${encodeURIComponent(projectId)}/deploy`, legacyUserId), { method: 'POST', headers, body: { ...(legacyUserId ? { userId: legacyUserId } : {}), githubUsername, githubToken, flyApiToken, }, timeoutMs: 60_000, }, ); ``` It can also receive environment and payment secrets: ```js const saveResult = await fetchJson( withUserId(`${cfg.apiBase}/project/${encodeURIComponent(projectId)}/env-files/save`, legacyUserId), { method: 'POST', headers, body: { filePath: envPath, variables: generatedVars, }, timeoutMs: 120_000, }, ); ``` ### Technical Analysis The ` ...[truncated 2844 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse the backend value with the standard `URL` class and reject malformed URLs, embedded credentials, fragments, and schemes other than HTTPS. 2. Allow the production endpoint only at an explicit hostname such as `https://api.launchpulse.ai`. 3. If local development must remain supported, permit HTTP only for loopback destinations such as `127.0.0.1`, `[::1]`, and carefully validated `localhost`. 4. Require explicit user confirmation before sending credentials to any non-default HTTPS hostname. 5. Do not forward a stored production PAT automatically to an overridden development backend. Require a separate development credential. 6. Apply a destination policy before constructing any authenticated request, not only during argument parsing. 7. Warn clearly when deployment, payment, environment, store, or domain-registration data will be transmitted to a non-default backend. 8. Prefer narrowly scoped, short-lived service credentials and separate tokens by operation. 9. Add automated tests covering attacker-controlled hosts, non-loopback HTTP addresses, embedded URL credentials, redirects, and unusual URL encodings. 10. Review redirect behavior and prevent authorization headers or sensitive bodies from being forwarded across origins. ]]>
