T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/read_mails.py:61
- Finding
- Credential Exfiltration Through an Unrestricted API Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/read_mails.py:61-65`, `scripts/read_mails.py:329-365`, and `scripts/read_mails.py:573-584` **Vulnerability Type**: Unrestricted credential-bearing outbound request **Risk Level**: High The script allows its API destination to be overridden through either the `--api-url` command-line argument or the `CLOUDFLARE_MAIL_MAILS_API_URL` environment variable. It then attaches the administrative credential and every configured optional authentication header to that destination without validating the URL's scheme, hostname, port, or path. Relevant configuration code: ```python parser.add_argument( "--api-url", default=os.getenv(ENV_API_URL, DEFAULT_API_URL), help=f"Admin API URL. Defaults to {DEFAULT_API_URL}.", ) ``` Authentication headers are assembled independently of the selected destination: ```python def build_headers(args: argparse.Namespace) -> tuple[Optional[dict[str, str]], Optional[str]]: admin_auth = args.admin_auth or os.getenv(ENV_ADMIN_AUTH) if not admin_auth: return None, f"missing admin credential: provide --admin-auth or {ENV_ADMIN_AUTH}" headers = { "Accept": "application/json", "Content-Type": "application/json", "x-admin-auth": admin_auth, } bearer_token = args.bearer_token or os.getenv(ENV_BEARER_TOKEN) if bearer_token: token = bearer_token.strip() if token: headers["Authorization"] = token if token.lower().startswith("bearer ") else f"Bearer {token}" custom_auth = args.custom_auth or os.getenv(ENV_CUSTOM_AUTH) if custom_auth: headers["x-custom-auth"] = custom_auth fingerprint = args.fingerprint or os.getenv(ENV_FINGERPRINT) if fingerprint: headers["x-fingerprint"] = fingerprint lang = args.lang or os.getenv(ENV_LANG) if lang: headers["x-lang"] = lang user_token = args.user_token or os.getenv(ENV_USER_TOKEN) if user_token: ...[truncated 3688 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Pin credentials to an approved origin** - Parse the URL with `urllib.parse.urlsplit`. - Require `https`. - Permit only an explicit allowlist of hostnames and ports. - Require the expected `/admin/mails` path. - Reject embedded user information, fragments, malformed ports, and ambiguous hostnames. 2. **Remove unrestricted endpoint overrides** - If custom deployments are unnecessary, remove `--api-url` and `CLOUDFLARE_MAIL_MAILS_API_URL`. - If they are necessary, require the origin to be added to trusted configuration separately from user-controlled invocation arguments. - Require explicit interactive confirmation before sending credentials to a non-default approved origin. 3. **Constrain redirects** - Disable automatic redirects for authenticated requests, or implement a redirect handler that revalidates every destination. - Never forward authentication headers when the scheme, hostname, or port changes. - Prefer failing closed and requiring a separately authenticated request to the new destination. 4. **Bind credentials to destinations** - Maintain separate credentials for each approved deployment. - Do not reuse the production administrative credential with development or user-supplied endpoints. - Use short-lived, mailbox-scoped tokens instead of a deployment-wide administrative secret where the backend supports them. 5. **Strengthen secret handling** - Prefer environment variables, protected secret stores, or standard input over command-line credential flags because command-line values may be exposed through process listings and shell history. - Redact authentication values from errors and diagnostic output. - Rotate all credentials if they may already have been used with an untrusted URL. 6. **Add regression tests** - Verify rejection of HTTP URLs, unapproved hosts, alternate ports, unexpected paths, user-information components, and cross-origin redirects. - ...[truncated 80 chars]
