T09 · Insecure Skill Coding Practices
- Location
scripts/run.py:96- Finding
Unrestricted API Endpoint Can Exfiltrate Credentials and Clinical Data
- Content
View full analysis
Vulnerability Details
File Location:
scripts/run.py:96-107,scripts/run.py:214,scripts/run.py:276-284
Vulnerability Type: User-controlled outbound destination with sensitive authorization and clinical data
Risk Level: MediumVulnerable Code
python def call_llm( *, api_url: str, model: str, appkey: str, system_prompt: str, user_prompt: str, temperature: float, timeout: int, ) -> str: payload = { "model": model, "temperature": temperature, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], } try: req = Request( api_url, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {appkey}", }, ) resp = urlopen(req, timeout=timeout)The destination is exposed as an unrestricted command-line option:
python p.add_argument("--api-url", default=DEFAULT_API_URL, help="OpenAI compatible endpoint URL")The user-controlled value and sensitive data are subsequently passed into the request:
python out["answer"] = call_llm( api_url=args.api_url, model=args.model, appkey=args.appkey, system_prompt=system_prompt_for(task_key, args.system_prompt), user_prompt=user_prompt, temperature=float(args.temperature), timeout=int(args.timeout), )Technical Analysis
The
--api-urlargument directly controls the destination supplied tourllib.request.Request. No validation restricts the URL scheme, destination hostname, port, or redirect target.Every request to this destination contains:
- The application key in the
Authorization: Bearerheader. - The complete clinical question in the JSON request body.
- The system prompt and model configuration.
- Potentially identifiab ...[truncated 1678 chars]
- The application key in the
- Remediation
View remediation
Remediation Suggestions
-
Restrict permitted endpoints
- Remove
--api-urlin production when endpoint customization is unnecessary. - Otherwise, maintain an explicit allowlist of trusted HTTPS hostnames and ports.
- Parse the URL with
urllib.parse.urlparseand reject unapproved schemes, hosts, ports, embedded credentials, fragments, and malformed values.
- Remove
-
Require transport security
- Accept only the
httpsscheme. - Reject plaintext HTTP even for user-supplied endpoints.
- Preserve normal TLS certificate and hostname verification.
- Accept only the
-
Control redirects
- Disable redirects for authenticated requests or validate every redirect destination against the same allowlist.
- Never forward the
Authorizationheader to a destination that has not been independently approved.
-
Limit credential exposure
- Use destination-specific, short-lived credentials with minimum permissions and restrictive quotas.
- Do not reuse a production key when testing custom endpoints.
- Consider retrieving credentials from a protected secret source rather than exposing them in process command-line arguments.
-
Protect clinical information
- Require de-identification before transmission.
- Minimize request data to fields required by the service.
- Record the approved destination in security logs without logging the bearer credential or clinical request body.
-
Validate response provenance
- Treat responses from non-default or development endpoints as untrusted.
- Clearly identify the selected endpoint in operator-visible output and require explicit confirmation before sending sensitive data to a non-production service.
-
