Back to skill

Security audit

ClawVoyant

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to do what it claims: search YouTube and retrieve transcripts, with no evidence of hidden data theft, persistence, or destructive behavior.

Reasonable to install if you accept that it sends search terms and video IDs to external services. The publisher should pin dependency versions, add bounds for max_results, and fix the install command so installation does not accidentally start the server.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:9
Finding
Unpinned Third-Party Dependencies Permit Unreviewed Package Versions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:9-14` **Vulnerability Type**: Insecure dependency version constraints **Risk Level**: Medium ### Vulnerable Code ```yaml requires: python: ">=3.10" pip: - duckduckgo_search>=6.0.0 - youtube-transcript-api>=0.6.0 - fastmcp>=0.1.0 install: "python scripts/server.py --install" ``` ### Technical Analysis All three Python dependencies use open-ended minimum-version constraints. No upper bounds, exact version pins, lockfile, or cryptographic package hashes are present in the audited project. Consequently, a future installation can resolve to dependency versions that were not present when the skill was reviewed. Python packages can execute code during installation or when imported. The application imports all three declared packages at module initialization in `scripts/server.py`. If an upstream package account, release process, or distribution channel is compromised, a malicious version satisfying these constraints could be installed and subsequently executed. This finding does not establish that the named packages are currently malicious. The risk arises from allowing future, unreviewed releases to enter the execution environment automatically. ### Attack Path 1. An attacker compromises an allowed upstream package, maintainer account, or package publication process. 2. The attacker publishes a malicious version greater than or equal to the minimum version declared in `SKILL.md`. 3. A user or deployment platform installs the skill and resolves dependencies without a lockfile or hash validation. 4. The package manager selects the attacker-controlled release because it satisfies the open-ended constraint. 5. Malicious code executes during package installation or when `scripts/server.py` imports the dependency. 6. The payload operates with the privileges and environmental access of the account running the installation or MCP server. ### Impact Assessment Successful exploitation co ...[truncated 396 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every dependency to an exact, reviewed version rather than using open-ended minimum constraints. 2. Generate and commit a lockfile containing the complete transitive dependency graph. 3. Require cryptographic hashes for downloaded distributions, such as by using a hash-locked requirements file and `pip install --require-hashes`. 4. Install packages only from an explicitly configured, trusted package index. 5. Add automated dependency vulnerability and provenance scanning to the release process. 6. Review and deliberately update dependency pins rather than accepting new upstream releases automatically. 7. Correct or remove the documented `--install` command because `scripts/server.py` does not implement that option and currently starts the MCP server instead. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/server.py:26
Finding
Unbounded Search Result Count Enables Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/server.py:26-32` and `scripts/server.py:69-75` **Vulnerability Type**: Missing input bounds and resource-consumption controls **Risk Level**: Low ### Vulnerable Code ```python def search(self, query: str, max_results: int = 5) -> List[Dict]: """Search YouTube and return a list of video details.""" results = [] search_query = f"{query} YouTube" raw_results = self.ddgs.text(search_query, max_results=max_results * 4) ``` The externally exposed MCP tool passes the caller-controlled value directly to the search method: ```python @mcp.tool() def search_youtube(query: str, max_results: int = 5) -> str: """ Search YouTube for videos. Returns a list of titles, URLs, and descriptions. """ results = cv.search(query, max_results=max_results) ``` ### Technical Analysis The MCP interface accepts a caller-controlled `max_results` integer without validating its range. The value is multiplied by four before being passed to the DuckDuckGo search client. A very large positive value can cause the server or its dependency to request, receive, iterate over, and format an excessive number of results. The code provides no explicit upper bound, request timeout, response-size limit, concurrency control, or per-caller rate limit. Even if the upstream service imposes its own limit, repeated oversized calls can still consume server connections, processing time, and upstream request quota. The final number of accepted YouTube results is nominally limited by `max_results`, but that does not mitigate the initial external request because the multiplied value is supplied before local filtering occurs. ### Attack Path 1. An attacker or malfunctioning MCP client invokes `search_youtube`. 2. The caller supplies an extremely large positive integer as `max_results`. 3. The tool forwards the value without validation to `ClawVoyant.search`. 4. The code multiplies the value by four and sup ...[truncated 838 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate `max_results` at the MCP boundary and reject non-integer, zero, negative, and oversized values. 2. Enforce a conservative range, such as between 1 and 20, before multiplying or forwarding the value. 3. Repeat validation inside `ClawVoyant.search` so direct library callers cannot bypass the MCP-layer check. 4. Configure explicit outbound request timeouts where supported by the DuckDuckGo client. 5. Apply per-client rate limiting and concurrency limits to the MCP server. 6. Limit response length and total formatted output size. 7. Return a clear validation error rather than silently accepting dangerous values. Example hardening: ```python MAX_RESULTS = 20 def search(self, query: str, max_results: int = 5) -> List[Dict]: if not isinstance(max_results, int) or isinstance(max_results, bool): raise ValueError("max_results must be an integer") if not 1 <= max_results <= MAX_RESULTS: raise ValueError(f"max_results must be between 1 and {MAX_RESULTS}") # Continue with the bounded request. ``` ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep

Static analysis

No suspicious patterns detected.