T09 · Insecure Skill Coding Practices
- Location
scripts/run.py:26- Finding
Unrestricted API Base URL Override Can Disclose Credentials
- Content
View full analysis
Vulnerability Details
File Location:
scripts/run.py:26-40, 85-93and duplicated indouyin-kol-search/scripts/run.py:26-40, 85-93
Vulnerability Type: Unvalidated credential-bearing request destination
Risk Level: MediumComplete Code Snippet
python def build_base_url(): return os.getenv("AISKILLS_BASE_URL", DEFAULT_BASE_URL).rstrip("/") def build_headers(): api_key = os.getenv("AISKILLS_API_KEY", "").strip() tenant_id = os.getenv("AISKILLS_TENANT_ID", "default").strip() or "default" if not api_key: fail("AISKILLS_API_KEY is required") return { "Content-Type": "application/json", # Cloudflare blocks urllib's default Python user agent for this endpoint. "User-Agent": "ai-skills-runner/1.0 (+https://ai-skills.ai)", "Accept": "application/json", "X-API-Key": api_key, "X-Tenant-Id": tenant_id, } def request_json(method, path, payload): body = json.dumps(payload).encode("utf-8") req = urllib.request.Request( f"{build_base_url()}{path}", data=body, method=method, headers=build_headers(), ) try: with urllib.request.urlopen(req, context=SSL_CONTEXT) as response: return json.loads(response.read().decode("utf-8"))Technical Analysis
The runner accepts
AISKILLS_BASE_URLwithout validating its scheme, hostname, port, or origin. It subsequently attachesAISKILLS_API_KEYandAISKILLS_TENANT_IDto every request sent to that destination.An attacker who can influence the process environment or deployment configuration can replace the legitimate endpoint with an attacker-controlled URL. The override can also use plaintext HTTP. The configured SSL context does not protect an HTTP request and does not prevent credential transmission to an unrelated HTTPS host with a valid certificate.
The same vulnerable implementation exists in both copies of the runner.
Attack Path
- The victim co ...[truncated 1128 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove
AISKILLS_BASE_URLconfigurability if endpoint overrides are unnecessary. - If overrides are required, parse the URL with
urllib.parse.urlsplit()and enforce:- The
httpsscheme. - An explicit allowlist of trusted hostnames.
- Approved ports only.
- No embedded username or password.
- No fragments or unexpected path components.
- The
- Reject plaintext HTTP even in development unless credentials are omitted and the mode is explicitly isolated.
- Prevent credential forwarding across origins. Disable redirects where practical or verify every redirect target before following it.
- Use a narrowly scoped API key with usage limits and rotation support.
- Apply the same fix to
douyin-kol-search/scripts/run.pyto keep both duplicated runners consistent. - Add tests confirming that untrusted hosts, plaintext schemes, embedded credentials, unexpected ports, and cross-origin redirects are rejected before request headers are created or transmitted.
- Remove
