Back to skill

Security audit

Book Fetch

Security checks for vulnerabilities and agentic risk

Overview

This skill automatically downloads ebooks from third-party archive sites and uploads them to MEGA, with broad activation wording and insufficient safeguards around what gets downloaded and uploaded.

Review before installing. Only use this skill when you explicitly want both the download and MEGA upload, understand the copyright and malware risks of third-party ebook sources, and are comfortable with it using your configured MEGA/rclone credentials. It should be tightened with confirmation prompts, strict URL allowlisting, safer temporary-file handling, and an option to search without uploading by default.

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/book_fetch.py:103
Finding

Unvalidated Remote URLs and Redirects Permit Server-Side Request Forgery

Content
View full analysis
str | None: """Fetch libgen.li ads page and extract the get.php direct link.""" try: resp = session.get(ads_url, timeout=15) resp.raise_for_status() soup = BeautifulSoup(resp.text, "lxml") for a in soup.select("a[href]"): href = a.get("href", "") if "get.php" in href and "md5=" in href and "key=" in href: return urljoin("https://libgen.li/", href) except Exception as e: print(f" libgen.li resolve failed: {e}") return None ``` ```python def download_file(url: str, dest_dir: Path, filename: str) -> Path | None: """Download file with progress bar.""" dest_dir.mkdir(parents=True, exist_ok=True) dest = dest_dir / filename print(f"⬇️ Downloading -> {dest}") try: resp = session.get(url, stream=True, timeout=60, allow_redirects=True) resp.raise_for_status() ``` ### Technical Analysis The application extracts links from remotely supplied H ...[truncated 2607 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/book_fetch.py:137
Finding

Predictable Shared Temporary Files Permit Symlink-Based File Overwrite

Content
View full analysis
Path | None: """Download file with progress bar.""" dest_dir.mkdir(parents=True, exist_ok=True) dest = dest_dir / filename print(f"⬇️ Downloading -> {dest}") try: resp = session.get(url, stream=True, timeout=60, allow_redirects=True) resp.raise_for_status() total = int(resp.headers.get("content-length", 0)) downloaded = 0 with open(dest, "wb") as f: ``` ```python def safe_filename(title: str, author: str, fmt: str) -> str: name = f"{title} - {author}" if author else title name = re.sub(r'[<>:"/\\|?*]', "", name) name = name[:120].strip() return f"{name}.{fmt}" ``` ### Technical Analysis Downloads are stored under the fixed, shared path `/tmp/books`. The destination filename is deterministic and is derived from remotely supplied title and author metadata. Although path separators and several special characters are removed, this sanitization does not address filesystem races, pre-existing symbolic links, predictable names, or directory ownership. The destination is opened with: ```python open(dest, "wb") ``` This operation follows symbolic links and truncates an existing target. It is not an exclusive or no-follow file creation operation. The application also calls `mkdir(..., exist_ok=True)` without checking whether `/tmp/books` already exists, whether it is a genuine directory, who owns it, or whether its permissions allow other local users to create entries. Consequently, another local account that can create the directory or entries within it may pre-create a symbolic link with a ...[truncated 1546 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill performs both network access and shell-adjacent operations (invoking Python, using rclone, and relying on host configuration) but declares no explicit tool scope or permission boundaries. In an agent environment, this creates an over-privileged integration where the skill may be invoked without transparent constraints, increasing the risk of unintended downloads, execution flow through external utilities, and exfiltration to remote storage.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger description is broad enough that ordinary requests like 'find an ebook' or 'download a book' could auto-select this skill in many contexts, even when the user did not clearly consent to downloading copyrighted material or uploading content to MEGA. Because the skill fetches from third-party sites and transfers files to cloud storage, overly permissive invocation language raises the chance of unsafe or policy-violating automation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The description does not clearly warn that the skill downloads files from untrusted external sources and then uploads them to remote cloud storage automatically. This omission is especially dangerous here because the content source is a piracy-oriented archive and the workflow can move potentially malicious or unauthorized files into persistent user storage without an obvious consent checkpoint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The request headers hard-code "Accept-Language" to "en-US,en;q=0.9", which imposes a specific language/locale on all outbound requests. This is a natural-language policy concern because the skill does not offer user opt-in or explain why English is required.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/book_fetch.py (reported line 179)May include surrounding context.

python
return upload_via_rclone(filepath, mega_folder)

    print(f"☁️  Uploading to MEGA:{mega_folder}/ ...")
    result = subprocess.run(
        ["mega-put", str(filepath), f"{mega_folder}/"],
        capture_output=True, text=True
    )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/book_fetch.py (reported line 201)May include surrounding context.

python
dest = f"mega:{mega_folder}/"
    print(f"☁️  Uploading via rclone -> {dest}")
    result = subprocess.run(
        ["rclone", "copy", str(filepath), dest, "--progress"],
        capture_output=True, text=True
    )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/book_fetch.py (reported line 216)May include surrounding context.

python
def _cmd_exists(cmd: str) -> bool:
    return subprocess.run(["which", cmd], capture_output=True).returncode == 0


# ── Filename sanitizer ────────────────────────────────────────────────────

Static analysis

No suspicious patterns detected.