Back to skill

Security audit

pdf2img

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward, user-invoked PDF-to-image converter with some resource-use and dependency-hardening caveats.

Install and run this only in a normal isolated Python environment, avoid untrusted or extremely large PDFs, keep scale values conservative, and prefer pinned dependency versions if reproducibility matters.

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/pdf_to_long_image.py:53
Finding
Unbounded PDF Rendering Can Exhaust Memory, CPU, and Disk Resources<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pdf_to_long_image.py:53-81`; scale input is accepted without bounds at `scripts/pdf_to_long_image.py:111-112` **Vulnerability Type**: Uncontrolled resource consumption **Risk Level**: Medium ### Vulnerable Code ```python # Render each page to image images = [] max_width = 0 total_height = 0 for page_num in range(page_count): page = doc[page_num] # Get page dimensions and apply scale mat = fitz.Matrix(scale, scale) pix = page.get_pixmap(matrix=mat) # Convert to PIL Image img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples) images.append(img) max_width = max(max_width, img.width) total_height += img.height print(f" Page {page_num + 1}/{page_count}: {img.width}x{img.height}") # Create combined image print(f"Creating long image: {max_width}x{total_height} pixels...") result = Image.new("RGB", (max_width, total_height), "white") y_offset = 0 for img in images: # Center images that are narrower than max width x_offset = (max_width - img.width) // 2 result.paste(img, (x_offset, y_offset)) y_offset += img.height ``` The scale parameter is exposed without a safe range: ```python parser.add_argument("--scale", type=float, default=2.0, help="Scale factor for rendering (default: 2.0)") ``` ### Technical Analysis The conversion routine does not impose limits on the input file size, page count, page dimensions, aggregate pixel count, output dimensions, or rendering scale. Each PDF page is rasterized and retained in the `images` list. After all page images are resident in memory, the script allocates an additional image large enough to contain every rendered page. Consequently, peak memory consumption includes the PyMuPDF pixel buffers, all retained Pillow page images, and the final combined image. Memory usage grows further with the square of the scale factor for ordinary two-dimensional pages. PNG compressio ...[truncated 1516 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `scale` to be finite and positive, and enforce a conservative upper bound. 2. Inspect page dimensions before rasterization and calculate the projected width, height, per-page pixels, and aggregate pixels. 3. Reject PDFs that exceed configured limits for input size, page count, individual page dimensions, total rendered pixels, or final output dimensions. 4. Account for multiple in-memory copies when estimating required memory; do not base limits solely on compressed PDF size. 5. Avoid retaining every page image simultaneously. Use bounded batches, temporary image tiles, or an output approach that supports incremental processing. 6. Set execution-level memory, CPU, timeout, and writable-storage quotas when processing untrusted files. 7. Catch Pillow and PyMuPDF allocation/decompression errors and remove partial output files on failure. 8. Consider offering separate per-page images when the projected long-image dimensions exceed safe limits. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:45
Finding
Third-Party Dependencies Are Installed Without Version or Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:45-49`; the same installation instruction also appears at `scripts/pdf_to_long_image.py:10-12` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```bash ## Dependencies The script requires these packages (install with uv): ```bash uv pip install pymupdf pillow ``` ``` The script documentation repeats the command: ```python Dependencies: uv pip install pymupdf pillow ``` ### Technical Analysis The documented installation command requests the latest package versions resolved under the user's current Python package-index configuration. It does not pin reviewed versions, use a lockfile, or verify artifact hashes. As a result, installations are not reproducible and the code imported by the skill can change without changes to the audited project. The package names shown are established packages rather than apparent typosquats, and the reviewed project does not configure an explicitly malicious repository. Therefore, this finding is a supply-chain hardening weakness rather than evidence that a malicious dependency is currently present. Exploitation requires compromise or substitution of an upstream release, package index, network/package-manager configuration, or resolved artifact. ### Attack Path 1. A user follows the documented `uv pip install pymupdf pillow` command. 2. The resolver queries package indexes configured in the user's environment and selects mutable package versions available at installation time. 3. An attacker who has compromised an upstream release, configured index, resolver environment, or distributed artifact causes a malicious version to be selected. 4. The dependency is installed and subsequently imported by the script through `import fitz` or `from PIL import Image`. 5. Malicious package initialization or runtime code executes with the privileges of the account running the installation or conversion. ### I ...[truncated 451 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin reviewed versions of PyMuPDF and Pillow rather than resolving unrestricted latest versions. 2. Maintain a lockfile containing exact transitive dependency versions and cryptographic hashes. 3. Install with hash verification enabled and fail installation when an artifact does not match the reviewed hash. 4. Use a trusted, explicitly configured package index and avoid unintended fallback to untrusted private or public indexes. 5. Perform dependency vulnerability and provenance checks as part of release maintenance. 6. Update pins deliberately after reviewing release notes, security advisories, and resolved artifacts. 7. Prefer installing dependencies in an isolated virtual environment with only the permissions required for PDF conversion. ]]>
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (1)

Session Persistence

Medium
Category
Rogue Agent
Content
description: |
  Convert multi-page PDFs into a single vertical long image by concatenating all pages.
  Use when the user asks to convert PDF to long image, combine PDF pages into one image,
  or create a scrolling screenshot from a PDF document.
---

# PDF to Long Image
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Static analysis

No suspicious patterns detected.