T09 · Insecure Skill Coding Practices
- Location
scripts/openapi.js:4- Finding
API Key Transmission to an Unvalidated Configurable Endpoint
- Content
View full analysis
Vulnerability Details
File Location:
scripts/openapi.js, lines 4 and 31–36
Vulnerability Type: Unvalidated destination for sensitive credential transmission
Risk Level: MediumVulnerable Code
js const BASE_URL = (process.env.SERVICE_API_BASE_URL || 'https://pre-st-api.699pic.com').replace(/\/+$/, '');js const res = await fetch(`${BASE_URL}${path}`, { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded', 'x-api-key': API_KEY, }, body, });Technical Analysis
The script reads
SERVICE_API_BASE_URLfrom the process environment without parsing or validating its scheme, hostname, port, or embedded credentials. It then sendsSERVICE_API_KEYto that destination in thex-api-keyheader on every API request.Credential transmission is necessary for the declared authenticated 699pic integration, and the default destination uses HTTPS. However, allowing an unrestricted override exceeds the minimum privilege necessary for that integration. A mistaken or attacker-controlled environment can redirect requests to an arbitrary server. An
http://endpoint would additionally transmit the API key and request parameters without transport encryption.The transmitted request body can contain search terms, content or asset identifiers, asset types, years, and download-record query parameters. No evidence of intentional credential theft or a hidden destination was found; the risk arises from insufficient destination validation.
Attack Path
- An attacker gains influence over the environment used to launch the Skill, such as deployment configuration, shell variables, an automation wrapper, or an untrusted MCP-related setup.
- The attacker sets
SERVICE_API_BASE_URLto a server they control, for examplehttps://attacker.example, or to a plaintext HTTP endpoint. - A user or agent invokes a command such as
search-photos,check-downloaded,download-asset, ordownload-records.
...[truncated 975 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse the configured endpoint with
new URL()and reject malformed values. - Require the
https:protocol in production. Permit plaintext HTTP only behind an explicit, disabled-by-default local-development option. - Allowlist authorized 699pic hostnames rather than accepting arbitrary destinations.
- If custom enterprise endpoints are required, maintain an explicit administrator-controlled allowlist and require confirmation before sending credentials to a newly configured host.
- Reject URLs containing embedded usernames or passwords, unexpected ports, fragments, or other unnecessary components.
- Disable or strictly validate redirects so the API key cannot be forwarded to another origin.
- Avoid including the API key, full endpoint, or sensitive response content in error logs.
- Use a narrowly scoped, revocable API key and rotate it immediately if an untrusted endpoint may have received it.
- Add automated tests covering malicious values such as
http://attacker.example, non-699pic HTTPS hosts, embedded credentials, and redirect responses.
A hardened initialization pattern should validate the destination before any authenticated request is made:
js const rawBaseUrl = process.env.SERVICE_API_BASE_URL || 'https://pre-st-api.699pic.com'; const parsedBaseUrl = new URL(rawBaseUrl); const allowedHosts = new Set([ 'pre-st-api.699pic.com', // Add explicitly approved production hosts here. ]); if (parsedBaseUrl.protocol !== 'https:') { throw new Error('SERVICE_API_BASE_URL must use HTTPS'); } if (!allowedHosts.has(parsedBaseUrl.hostname)) { throw new Error('SERVICE_API_BASE_URL host is not authorized'); } if (parsedBaseUrl.username || parsedBaseUrl.password) { throw new Error('Embedded URL credentials are not allowed'); } const BASE_URL = parsedBaseUrl.origin;- Parse the configured endpoint with
