T09 · Insecure Skill Coding Practices
- Location
scripts/kanbn_todo.py:54- Finding
Unvalidated API Base URL Enables Credential and Personal Data Exfiltration
- Content
View full analysis
Vulnerability Details
File Location:
scripts/kanbn_todo.py:54-91,scripts/kanbn_todo.py:117-129, andscripts/kanbn_todo.py:327-332
Vulnerability Type: Attacker-controlled network destination for authenticated requests
Risk Level: HighThe client accepts an arbitrary API base URL from a command-line argument, environment variable, or
~/.bashrc. It then sends the configured bearer token or API key to that destination without validating the URL scheme or hostname.Vulnerable Code
scripts/kanbn_todo.py:54-91:python class KanbnClient: def __init__(self, base_url, token=None, api_key=None, timeout=30): self.base_url = base_url.rstrip("/") self.token = token self.api_key = api_key self.timeout = timeout def request(self, method, path, params=None, body=None): query = "" if params: query = "?" + urllib.parse.urlencode(params, doseq=True) url = f"{self.base_url}{path}{query}" headers = { "Accept": "application/json", } # Some Kan.bn PUT endpoints require a JSON content-type even when the # request body is logically empty, so send an empty JSON object there. if body is not None: headers["Content-Type"] = "application/json" data = json.dumps(body).encode("utf-8") elif method.upper() in {"POST", "PUT", "PATCH"}: headers["Content-Type"] = "application/json" data = b"{}" else: data = None if self.token: headers["Authorization"] = f"Bearer {self.token}" if self.api_key: headers["x-api-key"] = self.api_key req = urllib.request.Request(url, data=data, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=self.timeout) as res:scripts/kanbn_todo.py:117-129:` ...[truncated 3381 chars]
- Remediation
View remediation
Remediation Suggestions
- Restrict the destination by default. Hard-code
https://kan.bn/api/v1when the Skill is intended exclusively for the official Kan.bn service. - Validate any required custom endpoint. Parse the URL with
urllib.parse.urlsplitand require:- The
httpsscheme. - A hostname on an explicit allowlist.
- An approved port.
- No username or password component.
- No fragment.
- The expected API path.
- The
- Require explicit user approval for custom deployments. Do not accept a custom endpoint solely from ambient configuration when credentials will be attached.
- Protect redirect handling. Disable automatic redirects or validate every redirect target before following it. Never forward authentication headers across origins.
- Remove the
~/.bashrcfallback. Shell startup files are an unnecessarily broad and mutable source for security-sensitive endpoint and credential configuration. Prefer process-scoped environment variables or a permission-restricted credential store. - Discourage command-line credentials. Values passed through
--tokenor--api-keymay be exposed through process listings or shell history. Prefer environment variables, standard input, or an operating-system credential store. - Fail closed. Reject invalid or unapproved destinations before constructing a request or loading authentication headers.
- Add security tests. Verify rejection of plaintext HTTP, unrelated domains, embedded credentials, unexpected ports, and cross-origin redirects.
- Restrict the destination by default. Hard-code
