Back to skill

Security audit

long-image-to-pdf

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its output handling can overwrite or delete files the user did not intend to touch.

Review this skill before installing. Use it only in a dedicated empty output directory, choose a simple PDF filename, and avoid enabling cleanup if you need to inspect intermediate images or if the output folder may contain existing files.

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/slice_and_pdf.py:91
Finding

Unrestricted PDF filename allows output-directory escape and arbitrary file overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/slice_and_pdf.py, lines 91-92 and 206-222
Vulnerability Type: Unrestricted file path and arbitrary file overwrite
Risk Level: High

Vulnerable Code

python
pdf_path = output_path / output_pdf_name
print(f"Generating PDF: {pdf_path}")

The value used by this operation is accepted directly from the command line:

python
parser.add_argument("--pdf-name", type=str,
                    default="output.pdf", help="Name of the output PDF file.")

# ...

slice_and_generate_pdf(
    source_image_path=args.source,
    output_dir=args.out_dir,
    output_pdf_name=args.pdf_name,
    slice_height=args.slice_height,
    overlap=args.overlap,
    images_per_row=args.cols,
    images_per_col=args.rows,
    layout=args.layout,
    cleanup=args.cleanup
)

Technical Analysis

The --pdf-name argument is treated as a trusted filename and joined directly to the selected output directory. No validation restricts it to a simple filename, checks its extension, rejects absolute paths, or prevents parent-directory traversal.

With pathlib, joining a path to an absolute second operand causes the original output directory to be discarded. Relative values containing .. can similarly resolve outside the intended output directory. The resulting path is passed to ReportLab's document builder, which can create or truncate the destination file.

Consequently, the output directory is not an effective security boundary. This is an arbitrary writable-file overwrite vulnerability rather than merely an output naming issue.

Attack Path

  1. The attacker influences the command arguments used to invoke the skill.
  2. The attacker supplies a valid source image and a writable output directory.
  3. The attacker sets --pdf-name to an absolute path or a traversal path, such as:
    text
    --pdf-name ../../target-file
    
    or:
    te

...[truncated 822 chars]

Remediation
View remediation

Remediation Suggestions

  • Require --pdf-name to be a simple filename rather than a path.
  • Reject absolute paths, path separators, . and .. components.
  • Enforce an expected .pdf suffix.
  • Resolve the final destination and verify that it remains beneath the resolved output directory.
  • Refuse to overwrite an existing file unless the user explicitly enables a dedicated overwrite option.
  • Where feasible, create the file using exclusive creation semantics to reduce race conditions.

Example containment validation:

python
requested_name = Path(output_pdf_name)

if requested_name.is_absolute() or requested_name.name != output_pdf_name:
    raise ValueError("--pdf-name must be a simple filename")

if requested_name.suffix.lower() != ".pdf":
    raise ValueError("--pdf-name must use the .pdf extension")

output_root = output_path.resolve()
pdf_path = (output_root / requested_name.name).resolve()

if output_root not in pdf_path.parents:
    raise ValueError("PDF destination escapes the output directory")

if pdf_path.exists():
    raise FileExistsError(f"Refusing to overwrite existing file: {pdf_path}")

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/slice_and_pdf.py:69
Finding

Predictable intermediate slice names can overwrite and delete unrelated files

Content
View full analysis

Vulnerability Details

File Location: scripts/slice_and_pdf.py, lines 69-75 and 165-171
Vulnerability Type: Unsafe temporary-file handling and destructive filename collision
Risk Level: Medium

Vulnerable Code

python
slice_filename = f"slice_{slice_index:04d}{save_suffix}"
slice_output_path_obj = output_path / slice_filename

slice_img.save(slice_output_path_obj, format=save_format)
slice_img.close()

sliced_image_paths.append(str(slice_output_path_obj))

The predictable files are subsequently removed when cleanup is enabled:

python
deleted_count = 0
if cleanup:
    for img_p in sliced_image_paths:
        try:
            Path(img_p).unlink(missing_ok=True)
            deleted_count += 1
        except Exception as e:
            print(
                f"Warning: Failed to delete intermediate file {img_p}: {e}")

Technical Analysis

Intermediate images are created directly inside the caller-selected output directory using deterministic names such as slice_0000.png. The script does not verify that these paths are absent, does not use exclusive file creation, and does not isolate temporary artifacts in a private directory.

If a matching file already exists, Pillow can overwrite it without warning. When --cleanup is enabled, the script then unlinks the path, causing the original file to be replaced and the replacement to be deleted.

Predictable paths also expose a time-of-check/time-of-use and symlink risk in shared or attacker-writable directories. An attacker able to create a matching symbolic link may cause the image write to follow that link and corrupt another writable file. Cleanup removes the link path afterward but does not restore the corrupted target.

Attack Path

A filename-collision attack can proceed as follows:

  1. The selected output directory already contains an unrelated file named slice_0000.png, or an attacker places such a file there ...[truncated 1133 chars]
Remediation
View remediation

Remediation Suggestions

  • Store intermediate slices in a private temporary subdirectory created with tempfile.TemporaryDirectory.
  • Generate randomized names rather than deterministic names in the user-selected output directory.
  • Ensure temporary directories are accessible only to the invoking user.
  • Refuse to follow symbolic links and avoid writing to pre-existing paths.
  • Track and delete only artifacts successfully created by the current invocation.
  • Keep the final PDF separate from the temporary slice directory.
  • Use a finally block or the temporary-directory context manager to provide reliable cleanup after success or failure.

Example hardening pattern:

python
import tempfile

with tempfile.TemporaryDirectory(
    prefix="long-image-slices-",
    dir=str(output_path)
) as temporary_directory:
    slice_directory = Path(temporary_directory)

    slice_filename = f"slice_{slice_index:04d}{save_suffix}"
    slice_output_path_obj = slice_directory / slice_filename

    if slice_output_path_obj.exists() or slice_output_path_obj.is_symlink():
        raise FileExistsError(
            f"Refusing to overwrite slice path: {slice_output_path_obj}"
        )

    slice_img.save(slice_output_path_obj, format=save_format)

The PDF must be completely built before the temporary-directory context ends because ReportLab reads the slice files during document generation.

Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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)

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
88% confidence
Finding

The skill instructs the agent to always add --cleanup by default, which causes automatic deletion of intermediate files without explicit user confirmation. This is a form of autonomous destructive decision-making: while limited to generated slices, it can still remove artifacts the user may need for verification, debugging, or recovery, especially if the script's cleanup scope is broader than expected.

Content

Scanner excerpt · SKILL.md (reported line 37)May include surrounding context.

md
* `--cols`: Number of columns in the PDF (default: `2`).
* `--rows`: Number of rows in the PDF (default: `2`).
* `--layout`: Arrangement sequence, either `grid` (left-to-right) or `column` (top-to-bottom) (default: `grid`).
* `--cleanup`: Add this flag to automatically delete the intermediate image slices after the PDF is created. (Highly recommended to save disk space unless the user explicitly asks to keep the sliced images).

## ⚠️ Important Instructions for the Agent (Guardrails)
1. **Always apply `--cleanup`** by default, unless the user specifically says "I want the sliced pictures too". Users generally only care about the final PDF.

Static analysis

No suspicious patterns detected.