Back to skill

Security audit

supabase-win

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Supabase read-only query helper, but it needs review because its API key handling can leak the key to an unintended host and its local credential safety guidance is incomplete.

Install only if you are comfortable reviewing or fixing the script first. Use only a Supabase anon key with strict Row Level Security, never a service-role key, verify the project ID is just the expected Supabase project reference, add a gitignore rule for references/.env, and rotate the key if it has already been committed or shared.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
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: High

Vulnerable 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_ID is 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/path produces:

text
https://attacker.example/path.supabase.co/rest/v1/users

The actual destination hostname is attacker.example, not Supabase. Nevertheless, the script attaches the configured Supabase anonymous key to both the apikey and Authorization headers before sending the request.

The fixed .supabase.co suffix therefore does not establish a trusted destination. This is an endpoint-injection issue that can result in credential disclosure.

Attack Path

  1. An attacker persuades a user or agent to configure the skill with an at ...[truncated 1248 chars]
Remediation
View remediation

Remediation Suggestions

  1. 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.
  2. Reject values containing dots, slashes, backslashes, colons, percent-encoding, whitespace, @, query delimiters, or fragment delimiters.
  3. 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.
  4. Build paths and query strings with URL-aware APIs rather than direct string interpolation.
  5. Add automated negative tests for values such as attacker.example/path, user@attacker.example, encoded delimiters, and whitespace.
  6. Do not attach authentication headers until destination validation has succeeded.

T09 · Insecure Skill Coding Practices

Warning
Location
references/SETUP.md:12
Finding

Plaintext Credential Configuration Is Not Protected by the Documented Git Ignore Control

Content
View full analysis

Vulnerability Details

File Location: references/SETUP.md, lines 12-16 and 28-32
Vulnerability Type: Insecure local credential storage and misleading security documentation
Risk Level: Medium

Vulnerable Documentation

markdown
## 2. Configure the Skill

1. Create file `references/.env`
2. Fill in your credentials:
   - `SUPABASE_PROJECT_ID=your-project-id`
   - `SUPABASE_ANON_KEY=your-anon-key`
markdown
## Security Notes

- The `.env` file is gitignored by default
- Never commit credentials to version control
- The anon key respects your Supabase RLS policies

Related instructions in SKILL.md, lines 30-33, also direct users to store the key in references/.env:

markdown
1. Copy `references/.env.example` to `references/.env`
2. Fill in your Supabase credentials in `references/.env`:
   - `SUPABASE_PROJECT_ID`: Your Supabase project ID (from project URL)
   - `SUPABASE_ANON_KEY`: Your anon/public API key (from Settings → API)

Technical Analysis

The setup process stores the API key in a plaintext file inside the project directory. The documentation claims this file is ignored by Git by default, but the audited project structure contains no .gitignore file implementing that protection.

Consequently, a user following the documented setup process may assume that references/.env cannot be committed when no such repository-level safeguard exists. The project also provides no guidance for applying restrictive filesystem permissions or using an environment variable or operating-system credential store.

The configured key is documented as a Supabase anonymous/public key rather than a service-role secret. It is therefore not equivalent to a privileged administrative credential. However, it still represents an authorization token whose effective capabilities depend on the project's grants and Row Level Security configuration, and accidental publication may expos ...[truncated 1233 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a repository-level .gitignore containing an explicit /references/.env rule.
  2. Include a non-secret references/.env.example containing placeholders only; the documentation currently references this file even though it is absent from the audited project.
  3. Prefer reading credentials from process environment variables or an operating-system credential store.
  4. If a local file remains supported, instruct users to restrict access to the owning account and avoid placing the file in shared or synchronized directories.
  5. Add a startup warning when the credential file has overly broad permissions on platforms where permissions can be checked reliably.
  6. Add secret-scanning and pre-commit checks to prevent accidental inclusion of .env files and Supabase tokens.
  7. Clarify that an anonymous key is publicly deployable only when database grants and Row Level Security policies have been securely configured; users must never substitute a service-role key.
  8. Revoke and rotate any key that has already been committed or distributed unintentionally.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (6)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/query.py (reported line 14)May include surrounding context.

python
import urllib.error
from pathlib import Path

# Configuration path - look for .env in references directory
SKILL_DIR = Path(__file__).parent.parent
ENV_FILE = SKILL_DIR / "references" / ".env"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/query.py (reported line 24)May include surrounding context.

python
import urllib.error
from pathlib import Path

# Configuration path - look for .env in references directory
SKILL_DIR = Path(__file__).parent.parent
ENV_FILE = SKILL_DIR / "references" / ".env"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/query.py (reported line 16)May include surrounding context.

python
# Configuration path - look for .env in references directory
SKILL_DIR = Path(__file__).parent.parent
ENV_FILE = SKILL_DIR / "references" / ".env"

# Default limits
MAX_ROWS = 200

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/query.py (reported line 92)May include surrounding context.

python
# Configuration path - look for .env in references directory
SKILL_DIR = Path(__file__).parent.parent
ENV_FILE = SKILL_DIR / "references" / ".env"

# Default limits
MAX_ROWS = 200

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/query.py (reported line 94)May include surrounding context.

python
# Configuration path - look for .env in references directory
SKILL_DIR = Path(__file__).parent.parent
ENV_FILE = SKILL_DIR / "references" / ".env"

# Default limits
MAX_ROWS = 200

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises file read and network-capable behavior but does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization gap where an agent runtime may grant broader-than-expected capabilities, increasing the risk of unintended file access or outbound network requests when handling sensitive local credentials like the Supabase anon key.

Content

No source excerpt is available for this finding.