Back to skill

Security audit

XY PubMed PDF Downloader

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its downloader can write outside the chosen download folder and overwrite existing PDF files if given a crafted filename.

Review before installing. Use only trusted identifiers and simple filenames without slashes or `..`, run it in a dedicated folder or virtual environment, and avoid letting untrusted text choose `--filename` or `--output` values. The publisher should constrain filenames to basenames, prevent accidental overwrites, and pin dependencies.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_pmc_pdf.py:115
Finding
Unrestricted Output Filename Allows Path Traversal and Arbitrary PDF File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download_pmc_pdf.py`, lines 115–138 **Vulnerability Type**: Path traversal and unrestricted file overwrite **Risk Level**: Medium ### Vulnerable Code ```python # Construct the output filename if not filename: filename = f"PMC{pmc_id}.pdf" if not filename.endswith(".pdf"): filename += ".pdf" output_path = self.output_dir / filename print(f"Processing: {identifier}") print(f"PMC ID: PMC{pmc_id}") print(f"Saving to: {output_path}") # Try Europe PMC europe_pmc_url = f"https://europepmc.org/backend/ptpmcrender.fcgi?accid=PMC{pmc_id}&blobtype=pdf" print(f"\nTrying [Europe PMC]: {europe_pmc_url}") try: response = self.session.get(europe_pmc_url, timeout=120, stream=True) if response.status_code == 200: content_type = response.headers.get('Content-Type', '').lower() with open(output_path, "wb") as f: ``` ### Technical Analysis The `filename` argument is derived from the user-controlled `--filename` command-line option and is joined directly to `self.output_dir`. The code does not reject absolute paths, parent-directory components such as `..`, or symbolic-link destinations. With `pathlib`, joining a base path to an absolute second path causes the base path to be discarded. A relative filename containing traversal components can similarly resolve outside the intended output directory. The destination is then opened in `wb` mode, which truncates an existing file before writing the downloaded response. Appending `.pdf` is not a sufficient path security control. It only limits the final suffix and still permits overwriting any writable destination ending in `.pdf`. Symbolic links can also redirect the operation to another writable PDF path. ### Attack Path 1. An attacker influences the filename passed to the Skill, for example: ```bash python3 scripts/download_pmc_pdf.py PMC12345678 \ -o ./downloads \ -f ../../important-document.pdf ``` 2. The sc ...[truncated 1184 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict custom filenames to a basename: ```python supplied_name = Path(filename) if supplied_name.is_absolute() or supplied_name.name != filename: raise ValueError("Filename must be a simple file name without directory components") ``` 2. Resolve the output directory and destination, then verify containment: ```python output_root = self.output_dir.resolve() output_path = (output_root / supplied_name.name).resolve() if output_root not in output_path.parents: raise ValueError("Output path escapes the configured output directory") ``` 3. Reject `.` and `..` path components explicitly. 4. Prevent unintended overwrites by opening the file in exclusive creation mode: ```python with open(output_path, "xb") as f: ... ``` Alternatively, require an explicit `--overwrite` option. 5. Check for symbolic links before writing and use platform-appropriate no-follow protections where available. 6. Download to a securely created temporary file inside the output directory, validate the completed file, and atomically rename it to the final destination only after all checks succeed. 7. Apply a maximum download size to prevent excessive disk consumption. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:80
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 80 **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Instruction ```bash pip install requests ``` ### Technical Analysis The installation instruction retrieves the latest version of `requests` and its transitive dependencies from the package index selected by the user's environment. No reviewed version, lockfile, package hash, or trusted-index requirement is specified. This creates a non-reproducible installation process. The effective dependency set can change after the Skill has been audited, and a future compromised, malicious, or incompatible release could be installed. The exposure also extends to transitive packages selected by the resolver. This is a supply-chain hardening weakness rather than evidence that the current `requests` package is malicious. ### Attack Path 1. A user follows the documented installation command. 2. `pip` contacts its configured package index or mirror. 3. The resolver selects the latest available `requests` release and compatible transitive dependencies. 4. If the selected index, mirror, release, or dependency has been compromised, attacker-controlled package code may be installed. 5. Package code can subsequently execute under the user's privileges during installation or when imported by the downloader. Successful exploitation depends on an upstream package, dependency, configured mirror, or package-index account being compromised. ### Impact Assessment Any malicious dependency code would run with the privileges of the user performing the installation or invoking the script. Depending on those privileges, the potential scope includes: - Reading or modifying user-accessible files. - Accessing environment variables and locally available credentials. - Making network requests. - Modifying the Python environment. - Affecting other applications that share the same environment. The practical likelihood is low ...[truncated 154 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin a reviewed dependency version rather than installing an unconstrained latest release: ```text requests==<reviewed-version> ``` 2. Maintain dependencies in a lockfile or requirements file with cryptographic hashes: ```bash pip install --require-hashes -r requirements.txt ``` 3. Pin and review transitive dependencies as well as the direct dependency. 4. Install dependencies inside a dedicated virtual environment rather than a shared or system Python environment. 5. Use an explicitly trusted package index and avoid untrusted mirrors: ```bash python3 -m pip install --index-url https://pypi.org/simple --require-hashes -r requirements.txt ``` 6. Add automated dependency vulnerability scanning and a controlled update process so pinned packages can receive reviewed security updates. ]]>
Vulnerability Patterns
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares network and file-read capable behavior in its documentation but does not explicitly constrain tool permissions or allowed tools. In agent environments, missing scope declarations can lead to over-broad execution privileges, making unintended network access or local file access more likely if the runtime grants defaults.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The markdown mixes an English header with the substantive usage instructions in Chinese, which effectively forces one language for users without opt-in. The policy explicitly calls for flagging language or locale constraints when the skill does not offer a user language choice or document a justified regional limitation.

Static analysis

No suspicious patterns detected.