T09 · Insecure Skill Coding Practices
- Location
scripts/query.py:43- Finding
Supabase API Key Disclosure Through Unvalidated Project Identifier
- Content
View full analysis
Vulnerability Details
File Location:
scripts/query.py, lines 43 and 86-101
Vulnerability Type: Unvalidated endpoint construction leading to credential disclosure
Risk Level: HighVulnerable Code
python def build_api_url(project_id, table, params): """Build Supabase REST API URL with query parameters.""" base_url = f"https://{project_id}.supabase.co/rest/v1/{table}"python project_id = config.get("SUPABASE_PROJECT_ID", "") anon_key = config.get("SUPABASE_ANON_KEY", "") if not project_id: return {"success": False, "error": "Missing SUPABASE_PROJECT_ID in .env"} if not anon_key: return {"success": False, "error": "Missing SUPABASE_ANON_KEY in .env"} url = build_api_url(project_id, table, params) headers = { "apikey": anon_key, "Authorization": f"Bearer {anon_key}", "Accept": "application/json" } try: req = urllib.request.Request(url, headers=headers, method="GET") with urllib.request.urlopen(req, timeout=TIMEOUT_SECONDS) as response:Technical Analysis
SUPABASE_PROJECT_IDis interpolated directly into the URL without validation. The code assumes that the resulting hostname will always be<project-id>.supabase.co, but URL delimiters in the project identifier can change how the URL is parsed.For example, the project identifier
attacker.example/pathproduces:text https://attacker.example/path.supabase.co/rest/v1/usersThe actual destination hostname is
attacker.example, not Supabase. Nevertheless, the script attaches the configured Supabase anonymous key to both theapikeyandAuthorizationheaders before sending the request.The fixed
.supabase.cosuffix therefore does not establish a trusted destination. This is an endpoint-injection issue that can result in credential disclosure.Attack Path
- An attacker persuades a user or agent to configure the skill with an at ...[truncated 1248 chars]
- Remediation
View remediation
Remediation Suggestions
- Validate the project identifier before constructing the URL. Permit only the expected Supabase project-reference character set and length, such as lowercase ASCII letters and digits.
- Reject values containing dots, slashes, backslashes, colons, percent-encoding, whitespace,
@, query delimiters, or fragment delimiters. - Parse the completed URL with
urllib.parse.urlsplit()and verify all of the following before attaching credentials:- The scheme is exactly
https. - No username or password is present.
- No unexpected port is present.
- The hostname is exactly
<validated-project-id>.supabase.co.
- The scheme is exactly
- Build paths and query strings with URL-aware APIs rather than direct string interpolation.
- Add automated negative tests for values such as
attacker.example/path,user@attacker.example, encoded delimiters, and whitespace. - Do not attach authentication headers until destination validation has succeeded.
