T09 · Insecure Skill Coding Practices
- Location
scripts/easydoc_mask.py:87- Finding
Unrestricted API Endpoint Override Can Exfiltrate API Credentials and Unredacted Medical Records
- Content
View full analysis
Vulnerability Details
File Location:
scripts/easydoc_mask.py:87-91,scripts/easydoc_mask.py:220-239, andscripts/easydoc_mask.py:428-435
Vulnerability Type: Unvalidated security-sensitive endpoint override
Risk Level: HighVulnerable Code
python parser.add_argument( "--base-url", default="", help="Optional base URL override.", )python def submit_task( api_key: str, base_url: str, file_paths: List[Path], custom_fields: List[str], timeout: int = 60, ) -> Dict: url = f"{base_url.rstrip('/')}{SUBMIT_PATH}" form_fields: List[Tuple[str, str]] = [("mode", MODE)] fields_to_use = custom_fields if custom_fields else DEFAULT_MASK_FIELDS properties = {field: {"type": "string"} for field in fields_to_use} schema = json.dumps({"properties": properties}, ensure_ascii=False) form_fields.append(("json_schema", schema)) payload, boundary = encode_multipart( fields=form_fields, files=[(FILE_FIELD, file_path) for file_path in file_paths], ) headers = { "api-key": api_key, "Content-Type": f"multipart/form-data; boundary={boundary}", } return http_json("POST", url, headers=headers, body=payload, timeout=timeout)python api_key = resolve_api_key(args.api_key) base_url = args.base_url.strip() or BASE_URL file_paths = [Path(p).expanduser().resolve() for p in args.file] if file_paths: validate_files(file_paths, skip_local_checks=args.skip_local_checks)Technical Analysis
The command-line
--base-urlvalue is used directly to construct submission and polling URLs. The implementation does not validate the URL scheme, hostname, port, user-information component, query, or fragment.The resulting POST request contains both:
- The EasyLink API credential in the
api-keyrequest header. - Complete source documents in the multi ...[truncated 2211 chars]
- The EasyLink API credential in the
- Remediation
View remediation
Remediation Suggestions
- Remove
--base-urland always use the documentedhttps://api.easylink-ai.comendpoint if alternate deployments are not a required feature. - If endpoint configurability is operationally necessary, enforce an explicit allowlist of trusted HTTPS origins. Validate the parsed URL rather than relying on string-prefix comparisons.
- Require:
- Scheme exactly equal to
https. - Hostname exactly equal to an approved host.
- An approved port, normally
443. - No URL user-information, query, or fragment components.
- Scheme exactly equal to
- Bind credentials to their intended origin. Never send the production EasyLink key to development, proxy, or custom endpoints; require separate credentials for each explicitly trusted deployment.
- Display the destination origin and obtain explicit confirmation before transmitting unredacted medical documents when any non-default deployment is supported.
- Add automated tests proving that HTTP URLs, subdomain tricks, embedded credentials, lookalike domains, redirects to unapproved origins, and arbitrary external hosts are rejected.
- Configure redirect handling so authentication headers and upload bodies are never forwarded to an origin outside the allowlist.
- Remove
