T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/migrate.py:36
- Finding
- ADC Bearer Token Disclosure Through Unrestricted API Base URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/migrate.py:36-39`, `scripts/migrate.py:47-50`, `scripts/migrate.py:247-248`, `scripts/migrate.py:283-286` **Vulnerability Type**: Credential disclosure through attacker-controlled request destinations **Risk Level**: High ### Vulnerable Code ```python def http_request(method: str, url: str, token: str, **kwargs) -> Dict[str, Any]: headers = kwargs.pop("headers", {}) headers.setdefault("Authorization", f"Bearer {token}") headers.setdefault("Content-Type", "application/json") response = requests.request(method, url, headers=headers, **kwargs) ``` ```python def wait_operation(base_url: str, op_name: str, token: str, timeout_s: int = 900) -> Dict[str, Any]: start = time.time() delay = 2.0 if op_name.startswith("http"): op_url = op_name else: op_url = f"{base_url}/{op_name}" ``` ```python parser.add_argument("--dfcx-base-url", default=DEFAULT_DFCX_BASE) parser.add_argument("--ces-base-url", default=DEFAULT_CES_BASE) ``` ```python token = get_access_token(list(set(DFCX_SCOPES + CES_SCOPES))) dfcx_agent = get_dfcx_agent(args.dfcx_base_url, args.dfcx_agent, token) ``` ### Technical Analysis The script accepts the Dialogflow CX and CES API base URLs directly from command-line arguments without validating their schemes, hosts, ports, or origins. Every request made through `http_request` receives the Google ADC bearer token in its `Authorization` header, regardless of the request destination. The acquired token requests the union of the Cloud Platform, Dialogflow, and CES scopes. Consequently, a custom endpoint does not merely receive migration data; it receives a live Google OAuth bearer token whose effective authority is determined by both the requested scopes and the IAM permissions of the executing identity. The long-running-operation logic introduces an additional trust-boundary issue. If an operation name starts with `http`, it is treated as an abs ...[truncated 2048 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Allowlist the expected Google API origins: - `https://dialogflow.googleapis.com` - `https://ces.googleapis.com` 2. Parse URLs with `urllib.parse.urlsplit` and reject: - Non-HTTPS schemes. - Embedded user information. - Unexpected hosts or ports. - Fragments and malformed authorities. 3. Validate every absolute operation URL against the validated origin before sending credentials. 4. Prefer resolving operation resource names against a fixed, trusted API base rather than accepting absolute operation URLs. 5. If custom endpoints are required for testing, require an explicit unsafe-development flag and do not send production ADC credentials to them. 6. Acquire separate least-privilege credentials for Dialogflow and CES instead of requesting the union of all scopes in one token. 7. Ensure errors and logs never print authorization headers or tokens. 8. Consider configuring short-lived credentials and monitoring API audit logs for token misuse. ]]>
