T09 · Insecure Skill Coding Practices
- Location
scripts/portfolio.py:70- Finding
API Credential Exposure Through a Configurable Untrusted Endpoint
- Content
View full analysis
OpenAI: api_key = os.environ.get("AISA_API_KEY") if not api_key: print("❌ Error: AISA_API_KEY environment variable is not set.", file=sys.stderr) sys.exit(1) base_url = os.environ.get("AISA_BASE_URL", "https://api.aisa.one/v1") return OpenAI(api_key=api_key, base_url=base_url) ``` ### Technical Analysis The client obtains the sensitive `AISA_API_KEY` credential from the environment but permits the API base URL to be replaced through `AISA_BASE_URL`. The replacement value is not validated against an approved hostname, URL scheme, or origin. The OpenAI client uses the supplied API key to authenticate requests sent through the configured base URL. Consequently, a party capable of controlling the Skill's process environment can redirect authenticated requests to an attacker-operated server. External networking is necessary for the declared live-pricing functionality. However, allowing credentials to be attached to requests for an arbitrary origin is broader than the minimum privilege required. The endpoint should be fixed to the declared AISA service or restricted to a narrowly defined allowlist. ### Attack Path 1. An attacker gains the ability to influence the environment used to launch the Skill, such as through a wrapper, deployment configuration, or inherited environment variable. 2. The attacker sets `AISA_BASE_URL` to an HTTPS endpoint under their control. 3. A user invokes the `show` command for a non-empty portfolio. 4. `fetch_prices()` calls `get_client()` and constructs an OpenAI client using the legitimate `AISA_API_KEY` and the attacker-controlled endpoint. 5. The client sends an authenticated pricing request to the attacker-operated server. 6. The attacker captures authentication ...[truncated 751 chars]- Remediation
View remediation
OpenAI: api_key = os.environ.get("AISA_API_KEY") if not api_key: raise RuntimeError("AISA_API_KEY is not configured") return OpenAI(api_key=api_key, base_url=AISA_BASE_URL) ``` 2. If custom endpoints are operationally required, parse the URL and enforce: - HTTPS only. - An exact allowlist of approved hostnames. - An expected port and path prefix. - Rejection of embedded credentials, fragments, unexpected redirects, and local or private-network destinations. 3. Configure the HTTP client not to forward authorization headers across cross-origin redirects. 4. Use a narrowly scoped API key with quota limits and rotation support. 5. Document every supported network destination in `SKILL.md` so users can make an informed disclosure decision. 6. Add tests confirming that malformed URLs, HTTP URLs, unapproved domains, loopback addresses, and private-network addresses are rejected before any authenticated request occurs. ]]>
