T09 · Insecure Skill Coding Practices
- Location
scripts/ima_tts_create.py:841- Finding
Unrestricted API Base URL Allows API Key and TTS Prompt Exfiltration
- Content
View full analysis
Vulnerability Details
File Location:
scripts/ima_tts_create.py:66-73, 550-554, 841-864, 922
Vulnerability Type: User-controlled network destination for authenticated requests
Risk Level: HighThe script permits callers to override the API base URL without validating its scheme, hostname, port, or trust relationship. The IMA API key is then attached to requests sent to that destination. This violates the documented guarantee that the credential is sent only to
api.imastudio.com.Vulnerable Code
Credential-bearing headers are constructed for all API requests:
python def make_headers(api_key: str, language: str = "en") -> dict: return { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "User-Agent": "IMA-OpenAPI-Client/Skill-1.0.0", "x-app-source": "ima_skills", "x_app_language": language, }Task creation sends the authenticated request, including the user-provided prompt in the generated payload, to the supplied base URL:
python url = f"{base_url}/open/v1/tasks/create" headers = make_headers(api_key) logger.info(f"Attempt {attempt_num}: attribute_id={attribute_id}, credit={credit}") try: resp = requests.post(url, json=payload, headers=headers, timeout=30)The command-line interface accepts an unrestricted destination:
python p.add_argument("--base-url", default=DEFAULT_BASE_URL, help="API base URL")That destination is used with the API key retrieved from either a command-line argument or the environment:
python def main(): args = build_parser().parse_args() base = args.base_url apikey = args.api_key or os.getenv("IMA_API_KEY") if not apikey: logger.error("API key is required. Use --api-key or set IMA_API_KEY environment variable") sys.exit(1) start_time = time.time() masked_key = f"{ap ...[truncated 3290 chars]- Remediation
View remediation
Remediation Suggestions
-
Remove the production endpoint override. Use the fixed
DEFAULT_BASE_URLfor all normal Skill execution:python base = "https://api.imastudio.com" -
If endpoint overrides are required for development, require explicit opt-in and exact allowlisting. Parse the URL and validate every relevant component:
python from urllib.parse import urlparse APPROVED_HOSTS = {"api.imastudio.com"} def validate_base_url(value: str) -> str: parsed = urlparse(value) if parsed.scheme != "https": raise ValueError("The API endpoint must use HTTPS") if parsed.hostname not in APPROVED_HOSTS: raise ValueError("Unapproved API hostname") if parsed.username or parsed.password: raise ValueError("Embedded URL credentials are prohibited") if parsed.port not in (None, 443): raise ValueError("Unexpected API port") return value.rstrip("/") -
Constrain redirects. Disable automatic redirects for credential-bearing requests or verify that every redirect target uses HTTPS and remains on the exact approved hostname before resending authorization headers.
-
Separate development credentials. If testing against non-production endpoints is genuinely necessary, use a distinct option that never accepts the production
IMA_API_KEYand requires a scoped test credential. -
Fully redact credentials from logs. The current code records the first ten characters of the API key. Replace this with a constant marker such as
api_key=[REDACTED]. -
Add security regression tests confirming rejection of:
- Plain HTTP URLs.
- Unapproved hostnames.
- Lookalike and subdomain hosts.
- URLs with embedded credentials.
- Unexpected ports.
- Cross-host redirects.
-
Align documentation with enforcement. Retain the claim that credentials are sent only to `api.ima ...[truncated 64 chars]
-
