Back to skill

Security audit

Volcengine Supabase

Security checks for vulnerabilities and agentic risk

Overview

This is a real Supabase administration skill, but its unsafe HTTP default and unreliable read-only guard create review-worthy risk for credentials and production data.

Review this before installing in any real workspace. Use only least-privilege Volcengine credentials, set SUPABASE_ENDPOINT_SCHEME=https, avoid get-keys --reveal unless deliberately handling secrets, do not rely on READ_ONLY to prevent SQL changes, and test destructive commands on an isolated branch first.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/volcengine_supabase/platform/aidap_client.py:27
Finding
Privileged Supabase service-role key transmitted over plaintext HTTP by default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/volcengine_supabase/platform/aidap_client.py:27,342-384`; `scripts/volcengine_supabase/tools/base.py:46-58`; `scripts/volcengine_supabase/platform/supabase_client.py:43-78` **Vulnerability Type**: Cleartext transmission of privileged credentials **Risk Level**: High ### Vulnerable Code ```python # scripts/volcengine_supabase/platform/aidap_client.py ENDPOINT_SCHEME = os.getenv("SUPABASE_ENDPOINT_SCHEME", "http").strip().lower() or "http" async def get_endpoint( self, workspace_id: str, branch_id: Optional[str] = None, use_cache: bool = True ) -> Optional[str]: # ... for domain in domains: if 'volces.com' in domain and 'ivolces.com' not in domain: if ENDPOINT_SCHEME == "https": result = f"https://{domain}" else: result = f"http://{domain}:80" endpoint_cache[cache_key] = result return result if domains: if ENDPOINT_SCHEME == "https": result = f"https://{domains[0]}" else: result = f"http://{domains[0]}:80" endpoint_cache[cache_key] = result return result ``` ```python # scripts/volcengine_supabase/tools/base.py async def _get_client( self, workspace_id: str, branch_id: Optional[str] = None ) -> SupabaseClient: endpoint = await self.aidap.get_endpoint(workspace_id, branch_id=branch_id) if not endpoint: target = branch_id or workspace_id raise ValueError(f"Could not get endpoint for target {target}") api_key = await self.aidap.get_api_key( workspace_id, "service_role", branch_id=branch_id ) if not api_key: target = branch_id or workspace_id raise ValueError(f"Could not get API key for target {target}") return SupabaseClient(endpoint, api_key) ``` ```python # scripts/volcengine_supabase/platform/supabase_client.py class SupabaseClient: ...[truncated 2835 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make HTTPS mandatory: - Change the default scheme to `https`. - Reject every scheme other than `https`; do not silently convert unknown values to HTTP. - Remove the port-80 construction path. 2. Validate discovered endpoints: - Parse endpoints with a standard URL parser. - Require an expected Volcengine/Supabase hostname suffix using label-aware comparison. - Reject IP literals, localhost, private-address destinations, user-info components, fragments, and unexpected ports. - Do not fall back to an arbitrary first domain. 3. Ensure certificate verification remains enabled and use an approved CA trust store. Consider certificate pinning where operationally feasible. 4. Use a less-privileged credential whenever a service-role key is unnecessary. 5. Rotate all service-role keys that may previously have traversed plaintext HTTP, and review access logs for unauthorized use. 6. Add automated tests asserting that privileged requests can never be emitted to an `http://` URL. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/volcengine_supabase/tools/database_tools.py:47
Finding
Read-only mode can be bypassed through arbitrary SQL execution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/volcengine_supabase/tools/database_tools.py:24-48,73-85,99-103` **Vulnerability Type**: Missing authorization enforcement on database operations **Risk Level**: High ### Vulnerable Code ```python class DatabaseTools(BaseTools): async def _execute_sql_raw( self, query: str, workspace_id: Optional[str] = None ) -> List[dict]: if not query or not query.strip(): raise ValueError("SQL query cannot be empty") ws_id, branch_id = await self._resolve_target(workspace_id) client = await self._get_client(ws_id, branch_id) result = await client.call_api( "/pg/query", method="POST", json_data={"query": query} ) # ... return result @handle_errors async def execute_sql( self, query: str, workspace_id: Optional[str] = None ) -> List[dict]: return await self._execute_sql_raw(query, workspace_id) @handle_errors async def list_migrations( self, workspace_id: Optional[str] = None ) -> List[dict]: query = """ CREATE SCHEMA IF NOT EXISTS supabase_migrations; CREATE TABLE IF NOT EXISTS supabase_migrations.schema_migrations ( version text PRIMARY KEY, name text NOT NULL, inserted_at timestamptz NOT NULL DEFAULT now() ); SELECT version, name FROM supabase_migrations.schema_migrations ORDER BY version DESC """ return await self._execute_sql_raw(query, workspace_id) @handle_errors @read_only_check async def apply_migration( self, name: str, query: str, workspace_id: Optional[str] = None ) -> dict: # ... ``` ### Technical Analysis `execute_sql` accepts arbitrary SQL and calls the privileged `/pg/query` endpoint using the service-role client. Unlike `apply ...[truncated 2081 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply `@read_only_check` to `execute_sql`, but do not rely only on the decorator. 2. Enforce read-only behavior at the lowest-level execution boundary: - In `_execute_sql_raw`, use a genuinely read-only database transaction or account when `READ_ONLY` is enabled. - Configure the transaction as `READ ONLY`. - Use a database role that lacks DDL and DML permissions. 3. For defense in depth, parse SQL using a PostgreSQL-aware parser and reject all statements except an explicit read-only allowlist. Simple keyword matching is insufficient because of comments, CTEs, writable functions, and multi-statement queries. 4. Change `list_migrations` so it only performs a `SELECT`. Move schema/table initialization to a guarded migration or initialization command. 5. Separate query functionality into: - A read-only query action backed by a read-only role. - An explicitly named mutation action requiring confirmation and write authorization. 6. Add tests covering `INSERT`, `UPDATE`, `DELETE`, `DROP`, `ALTER`, writable CTEs, stored-function calls, and multi-statement SQL while `READ_ONLY=true`. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Dependencies are not reproducibly pinned and include a third-party GitHub fork<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-3` **Vulnerability Type**: Insecure dependency and supply-chain configuration **Risk Level**: Medium ### Vulnerable Code ```text httpx>=0.27.0 pydantic>=2.0.0 git+https://github.com/sjcsjcsjc/volcengine-python-sdk.git@9905a8853a0e5fd26fdae93eefb4f201e8bef539 ``` ### Technical Analysis The package permits any future version of `httpx` and `pydantic` satisfying the lower bounds. Installation is therefore not reproducible and may silently consume a newly released, compromised, or backward-incompatible version. The Volcengine SDK is installed directly from a GitHub repository under the `sjcsjcsjc` account rather than from a clearly identified official package source. It is pinned to a commit, which prevents that reference from normally changing in place and is safer than installing from a moving branch. However, the dependency still executes packaging and installation code obtained from an external third-party repository, and no hash or documented provenance verification is provided. This SDK is especially sensitive because it receives the Volcengine access key, secret key, and session token during client initialization. ### Attack Path 1. The operator follows `SKILL.md` and runs `pip install -r requirements.txt` or `uv pip install -r requirements.txt`. 2. The installer resolves unrestricted future versions of `httpx` and `pydantic` and clones the GitHub-hosted SDK. 3. A compromised package release, compromised repository/account, malicious transitive dependency, or substituted source is installed. 4. Installation hooks or imported runtime code execute locally. 5. Because the SDK is initialized with Volcengine credentials, compromised code can access those credentials and potentially transmit them or alter management requests. The pinned Git commit reduces, but does not eliminate, the Git dependency risk. ### Impact Assessment A compromised dependency executes with the privileges of ...[truncated 600 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the GitHub fork with an official, verified Volcengine distribution where available. 2. If the fork is unavoidable: - Document why it is trusted and how the commit was reviewed. - Mirror the reviewed source into an organization-controlled repository or artifact registry. - Build a signed wheel in a trusted pipeline. - Verify artifact hashes during installation. 3. Pin every direct and transitive dependency to an exact reviewed version using a lock file. 4. Use hash-verified installation, such as a generated requirements file with `--require-hashes`. 5. Run dependency vulnerability and provenance scanning in CI. 6. Install dependencies in an isolated environment without production credentials, then run the Skill under a constrained account with least-privilege credentials. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/volcengine_supabase/tools/storage_tools.py:94
Finding
Unescaped bucket name permits privileged API path manipulation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/volcengine_supabase/tools/storage_tools.py:94-103` **Vulnerability Type**: Improper neutralization of user input in a URL path **Risk Level**: Medium ### Vulnerable Code ```python @handle_errors @read_only_check async def delete_storage_bucket( self, bucket_name: str, workspace_id: Optional[str] = None ) -> dict: if not bucket_name or not bucket_name.strip(): raise ValueError("Bucket name cannot be empty") ws_id, branch_id = await self._resolve_target(workspace_id) client = await self._get_client(ws_id, branch_id) response = await client.call_api( f"/storage/v1/bucket/{bucket_name}", method="DELETE" ) if isinstance(response, dict) and "error" in response: raise ValueError(response["error"]) return {"success": True, "message": "Bucket deleted successfully"} ``` ### Technical Analysis `bucket_name` is inserted directly into a URL path. Validation only checks that it is non-empty. Unlike Edge Function names, which are encoded with `urllib.parse.quote(..., safe="")`, bucket names are neither allowlisted nor percent-encoded. A value containing `/`, `..`, `?`, `#`, or encoded separator sequences can change how the HTTP client or server interprets the request target. Dot-segment normalization may direct the authenticated `DELETE` request to another Storage API route, while slashes can introduce additional path segments. The request is authenticated with the service-role key, increasing the consequences of routing a request to an unintended endpoint. Exact behavior depends on HTTPX and server-side URL normalization, but the code fails to preserve the bucket name as one opaque path segment. ### Attack Path 1. An attacker or untrusted agent input controls the `--bucket-name` argument. 2. The attacker supplies a crafted value containing path-control characters, for example a dot-segment sequence or an additional path suffix. 3. The ...[truncated 1047 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate bucket names against the exact Supabase naming rules before constructing the URL. Reject: - `/` and `\` - `.` and `..` path segments - Control characters - `?`, `#`, `%`, and other URL delimiters unless explicitly permitted 2. Encode the name as one path segment: ```python from urllib.parse import quote encoded_name = quote(bucket_name, safe="") response = await client.call_api( f"/storage/v1/bucket/{encoded_name}", method="DELETE" ) ``` 3. Prefer a centralized URL builder that accepts path segments separately and safely encodes each one. 4. Add tests for slashes, backslashes, `..`, percent-encoded separators, query delimiters, fragments, Unicode normalization, and control characters. 5. Verify deletion by listing buckets and confirming that only the exact intended bucket was removed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (47)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill includes a sensitive credential-retrieval capability (`get-keys`) that is not clearly disclosed in the top-level description. Understating secret-access functionality can mislead users and orchestration layers into approving or invoking a skill without appreciating that it can expose API keys, especially since the documentation notes a `--reveal` option for unmasking them.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill includes a sensitive credential-retrieval capability (`get-keys`) that is not clearly disclosed in the top-level description. Understating secret-access functionality can mislead users and orchestration layers into approving or invoking a skill without appreciating that it can expose API keys, especially since the documentation notes a `--reveal` option for unmasking them.

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Functions, Storage, and TypeScript type generation via a local CLI. Run uv run ./scripts/call_volcengine_supabase.py to get real-time results.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
98% confidence
Finding
The RLS snippet grants unrestricted public read/write/delete access and presents it as a quick configuration without warning about the security consequences. Because this skill manages Supabase resources and encourages direct execution of SQL, a user could deploy these policies and unintentionally expose an entire table to anonymous attackers.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
`apply_migration` executes clearly state-changing SQL (`CREATE SCHEMA`, `CREATE TABLE`, arbitrary migration SQL, and `INSERT`) while being decorated with `@read_only_check`. If the read-only guard relies on metadata or naming, this misclassification can bypass safety controls and let callers perform schema/data modifications in contexts that should prohibit writes.

Missing User Warnings

High
Confidence
95% confidence
Finding
The API exposes retrieval of sensitive credentials and allows full secret disclosure when reveal=true, including the service_role_key, which is typically a high-privilege secret. In an agent skill context, this is dangerous because downstream prompts, logs, tool outputs, or untrusted users could coerce the agent into exfiltrating credentials without an additional privilege check or explicit secret-handling control in this code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises executable CLI behavior and references environment variables, local files, and remote API access, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates a governance gap: consumers cannot easily constrain or review what capabilities the skill may exercise, increasing the chance of unintended secret access, local file reads, or network actions.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The primary heading and core behavioral description are written entirely in Chinese, presenting the skill as operating in that language without any opt-in or alternative locale guidance. Under the policy, language constraints should be optional or clearly justified; no such user choice or justification appears here.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This markdown file includes a command to delete an Edge Function, which can remove deployed functionality and affect system availability. The surrounding guidance labels the command but does not provide a clear warning about its destructive nature or recommend confirming the target before execution.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The title and introductory text are written entirely in Chinese and present the guide as a general schema/migration reference, but there is no indication that the skill is region-specific or that users may opt into this language. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The playbook includes live `INSERT`, `UPDATE`, and `DELETE` examples without any warning that they modify persistent data. In an operational skill designed to run real-time SQL via a local CLI, users may copy and execute these statements against production or shared environments, causing unintended data loss or corruption.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The documented RLS example enables row-level security and then immediately creates policies that allow unrestricted public SELECT, INSERT, UPDATE, and DELETE using `true` conditions. In a Supabase context, this effectively exposes the table to any client using the public API, defeating the purpose of RLS and creating a high likelihood of unauthorized data access or tampering.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The reference exposes destructive branch operations such as delete and reset with only a brief generic note and no explicit warning, confirmation requirement, or guardrails. In an agent skill, this increases the chance that an LLM or user will invoke irreversible actions against the wrong workspace or branch, causing data loss or environment disruption.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documented edge function deployment/deletion and storage bucket creation/deletion commands can directly modify production behavior or remove data, yet the reference provides no explicit safety guidance, approval requirements, or environment scoping. In the context of a real CLI-backed management skill, this can lead to unintended code deployment, public exposure of storage, or destructive deletion by an automated agent.

Static analysis

No suspicious patterns detected.