T09 · Insecure Skill Coding Practices
- Location
scripts/todoist_api.py:207- Finding
Bearer Token Can Be Transmitted to an Arbitrary or Plaintext Destination
- Content
View full analysis
Vulnerability Details
File Location:
scripts/todoist_api.py:139-143, 207-217, 2300-2301;scripts/smoke_test.py:37-52
Vulnerability Type: Unrestricted credential destination and insecure transport configuration
Risk Level: HighVulnerable Code
scripts/todoist_api.py:139-143:python def with_base(base_url: str, path: str) -> str: base = base_url.rstrip("/") if not path.startswith("/"): path = "/" + path return f"{base}{path}"scripts/todoist_api.py:207-217:python url = with_base(base_url, path) if query: encoded_query = urllib.parse.urlencode( {k: v for k, v in query.items() if v is not None}, doseq=True, ) if encoded_query: url = f"{url}?{encoded_query}" headers = { "Authorization": f"Bearer {token}",scripts/todoist_api.py:2300-2301:python parser.add_argument("--token", help="Todoist API token. Defaults to TODOIST_API_TOKEN.") parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help=f"API base URL (default: {DEFAULT_BASE_URL})")scripts/smoke_test.py:37-52:python parser.add_argument("--token", help="Todoist API token. Defaults to TODOIST_API_TOKEN.") parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help=f"API base URL (default: {DEFAULT_BASE_URL})") parser.add_argument("--timeout", type=int, default=20, help="HTTP timeout in seconds (default: 20).") args = parser.parse_args(argv) token = args.token or os.getenv("TODOIST_API_TOKEN") or os.getenv("TODOIST_TOKEN") if not token: emit({"ok": False, "error": "Missing Todoist token. Pass --token or set TODOIST_API_TOKEN."}) return 2 url = args.base_url.rstrip("/") + "/projects?" + urllib.parse.urlencode({"limit": 1}) request = urllib.request.Request( url=url, method="GET", ...[truncated 2611 chars]- Remediation
View remediation
Remediation Suggestions
- Remove
--base-urlfrom production-facing commands unless custom endpoints are an essential requirement. - Centralize endpoint validation and apply it to both scripts before retrieving or attaching the token.
- Require the
httpsscheme and reject embedded credentials, fragments, unexpected ports, and malformed URLs. - Allowlist the exact official API origin, such as
https://api.todoist.com, including the expected API path prefix. - If development endpoints are required, place them behind an explicit unsafe-development option and require a separate non-production credential.
- Disable redirects for authenticated requests or validate every redirect target and strip authorization whenever the scheme, hostname, or port changes.
- Add tests proving that HTTP URLs, lookalike domains, subdomain tricks, user-info URLs, and cross-origin redirects are rejected.
- Document that agent-generated or user-supplied URLs must never determine the destination of a request carrying a Todoist credential.
- Remove
