T09 · Insecure Skill Coding Practices
- Location
scripts/patentmax_roadmap.py:38- Finding
Unrestricted API Base URL Can Expose Credentials and Confidential Patent Data
- Content
View full analysis
Vulnerability Details
File Location:
scripts/patentmax_roadmap.py, lines 38 and 76–80
Vulnerability Type: Unrestricted service endpoint override resulting in credential and sensitive-data disclosure
Risk Level: HighComplete Code Snippet
python BASE_URL = os.environ.get("PATENTMAX_BASE_URL", "https://api.ip930.com").rstrip("/") API_KEY = os.environ.get("PATENTMAX_API_KEY", "").strip()python url = path if path.startswith("http") else f"{BASE_URL}{path}" data = json.dumps(body, ensure_ascii=False).encode("utf-8") if body is not None else None req = urllib.request.Request(url, data=data, method=method) req.add_header("Authorization", f"Bearer {API_KEY}") req.add_header("Accept", "application/json")Technical Analysis
The client accepts
PATENTMAX_BASE_URLdirectly from the process environment without validating its scheme, hostname, port, or destination. The sharedrequest()function then attaches the PatentMax bearer token to every request sent through that endpoint.Consequently, a party capable of influencing the process environment can redirect requests to an attacker-controlled server. The code does not require HTTPS and does not restrict the destination to
api.ip930.com. For report-creation requests, the request body may also contain unpublished technical materials, experimental evidence, future business plans, patent assets, budgets, competitors, disclosure dates, and confidentiality boundaries.This issue does not independently grant an external attacker control of the environment. Exploitation requires control over, or influence on, the environment used to launch the Skill—for example, a compromised wrapper, CI configuration, shell profile, container configuration, or agent runtime.
Attack Path
- An attacker gains the ability to modify the environment from which the Skill is launched.
- The attacker sets
PATENTMAX_BASE_URLto an attacker-controlled endpoint, such ashttps://attacker.example.
...[truncated 1259 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove the production
PATENTMAX_BASE_URLoverride if runtime endpoint customization is unnecessary. - If an override is required for testing, parse and strictly validate it with
urllib.parse.urlsplit. - Require the
httpsscheme and reject plaintext HTTP. - Allowlist exact approved hostnames, such as
api.ip930.com; do not rely on substring or suffix matching. - Reject embedded credentials, fragments, unexpected ports, malformed URLs, and non-empty paths where a host-only base URL is expected.
- Use separate, minimally privileged test credentials for development endpoints. Never send production credentials to configurable test hosts.
- Require an explicit development-only flag before permitting a non-production endpoint, and fail closed by default.
- Before adding the
Authorizationheader, verify that the final request destination remains an approved origin. - Review redirect behavior and prevent authorization headers from reaching untrusted redirect targets.
- Rotate any API key that may have been used while the endpoint environment was untrusted, and review service logs for unauthorized report creation or data access.
A hardened validation pattern should enforce the approved origin before any authenticated request is created:
python from urllib.parse import urlsplit APPROVED_HOSTS = {"api.ip930.com"} def validate_base_url(value): parsed = urlsplit(value) if parsed.scheme != "https": raise ValueError("The API endpoint must use HTTPS.") if parsed.hostname not in APPROVED_HOSTS: raise ValueError("The API endpoint host is not approved.") if parsed.username or parsed.password or parsed.fragment: raise ValueError("Credentials and fragments are not permitted.") if parsed.port not in (None, 443): raise ValueError("Unexpected API endpoint port.") return f"https://{parsed.hostname}"- Remove the production
