Back to skill

Security audit

Pdf Parser Agent

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward local PDF parser, but users should choose input and output paths carefully and be aware it relies on an unpinned third-party package.

Install only from a trusted Python package source, preferably in an isolated environment with a pinned dependency. Run the skill only on PDFs you intend to parse, and use an output directory inside your workspace because the script does not enforce that boundary itself.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/pdf_extractor.py:10
Finding

Workspace Input Path Validation Can Be Bypassed

Content
View full analysis

Vulnerability Details

File Location: scripts/pdf_extractor.py, lines 10-13
Vulnerability Type: Improper path containment validation
Risk Level: Medium

Vulnerable Code:

python
# SECURITY: Path traversal validation
abs_input_path = os.path.abspath(input_path)
if not abs_input_path.startswith(os.path.abspath(".")):
    print(f"SECURITY ERROR: Path traversal detected. Input path '{input_path}' resolves outside of workspace.")
    sys.exit(1)

Technical Analysis

The code attempts to restrict PDF input files to the current workspace by comparing path strings with startswith(). String-prefix matching does not prove that one filesystem path is contained within another.

For example, if the workspace is /tmp/app, the path /tmp/app-secret/document.pdf starts with /tmp/app even though it is located in a sibling directory. In addition, os.path.abspath() normalizes path syntax but does not resolve symbolic links. A symbolic link stored inside the workspace can therefore point to a PDF outside the workspace and still pass this validation.

The subsequent os.path.isfile(input_path) check only verifies that the supplied path resolves to a regular file. It does not establish that the resolved file remains inside the intended workspace.

Attack Path

  1. The attacker identifies a readable PDF outside the intended workspace.
  2. The attacker supplies either:
    • A path in a sibling directory whose name begins with the workspace path, or
    • A symbolic link inside the workspace that points to the external PDF.
  3. os.path.abspath() produces a path whose string passes the startswith() check.
  4. os.path.isfile() follows the path or symbolic link and confirms that the target is a regular file.
  5. opendataloader_pdf.convert() reads and processes the external PDF.

Impact Assessment

Successful exploitation allows access to PDF files outside the intended workspace, subject to t ...[truncated 330 chars]

Remediation
View remediation

Remediation Suggestions

Resolve the workspace and candidate paths to their canonical filesystem locations before checking containment. Use path-aware containment instead of string-prefix matching.

python
from pathlib import Path

workspace = Path.cwd().resolve()
candidate = Path(input_path).resolve(strict=True)

if not candidate.is_relative_to(workspace):
    raise ValueError("Input file must remain inside the workspace")

if not candidate.is_file():
    raise ValueError("Input path must reference a regular file")

For Python versions without Path.is_relative_to(), compare canonical paths with os.path.commonpath(). If symbolic links are unnecessary, explicitly reject them and consider validating each path component to prevent symlink-based redirection.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/pdf_extractor.py:20
Finding

Caller-Controlled Output Directory Is Not Restricted to the Workspace

Content
View full analysis

Vulnerability Details

File Location: scripts/pdf_extractor.py, lines 20-29 and 43
Vulnerability Type: Unrestricted filesystem output path
Risk Level: Medium

Vulnerable Code:

python
# SECURITY: Output directory sanitization is left to the underlying library/API call.

print(f"Parsing '{input_path}' to {formats} in '{output_dir}'...")
try:
    opendataloader_pdf.convert(
        input_path=input_path,
        output_dir=output_dir,
        format=formats
    )
    print("Conversion successful. Check the output directory.")
python
output_dir = sys.argv[2] if len(sys.argv) > 2 else "output/parsed_pdf"

Technical Analysis

The optional output directory is accepted directly from the command line and passed to opendataloader_pdf.convert() without canonicalization, containment validation, or symlink checks. The source comment explicitly delegates output sanitization to the dependency, but that does not enforce this skill's intended workspace boundary.

A caller can provide an absolute path or a relative path containing traversal components. If the underlying converter creates or replaces generated files in that directory, output can be written outside the project workspace. Symbolic links in the output path may provide another way to redirect writes.

The exact generated filenames and replacement behavior depend on opendataloader_pdf, but the project itself imposes no restriction on the destination.

Attack Path

  1. The attacker selects a directory outside the workspace that is writable by the Agent process.
  2. The attacker invokes the script with that directory as the second command-line argument, using an absolute path or traversal path such as ../../target.
  3. The value is assigned directly to output_dir.
  4. The unrestricted value is passed to opendataloader_pdf.convert().
  5. The converter creates generated Markdown or JSON files in the attacker-selected d ...[truncated 631 chars]
Remediation
View remediation

Remediation Suggestions

Restrict all output to a dedicated directory beneath the workspace. Resolve the requested output path and verify containment before invoking the converter.

python
from pathlib import Path

workspace = Path.cwd().resolve()
output_root = (workspace / "output").resolve()
requested_output = Path(output_dir)

if not requested_output.is_absolute():
    requested_output = workspace / requested_output

resolved_output = requested_output.resolve()

if not resolved_output.is_relative_to(output_root):
    raise ValueError("Output directory must remain under the workspace output directory")

resolved_output.mkdir(parents=True, exist_ok=True)

Additionally:

  • Reject symbolic-link path components if they are not required.
  • Avoid replacing existing files by default.
  • Generate unpredictable or collision-resistant output names where appropriate.
  • Verify that the dependency's actual output files remain beneath the approved directory after conversion.
  • Pass the validated canonical path, rather than the original caller-provided string, to the dependency.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:8
Finding

Third-Party PDF Parser Dependency Is Installed Without Version or Integrity Pinning

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 8-14
Vulnerability Type: Unpinned third-party dependency
Risk Level: Medium

Vulnerable Code:

markdown
## Dependencies
This skill requires Python packages installed system-wide or user-site-wide:
1. `opendataloader-pdf`

## Usage Example
The skill's execution script dynamically finds the correct user-site packages path, assuming the user has installed the dependency via `pip install --user opendataloader-pdf`.

Technical Analysis

The documented installation command retrieves an unconstrained release of opendataloader-pdf. No reviewed version, lock file, package hash, or trusted package-index configuration is provided.

Consequently, the effective dependency code can change after this skill has been audited. A compromised upstream account, malicious future release, or unsafe package source could introduce code that executes during package installation or when opendataloader_pdf is imported.

Installation into the user site also makes the dependency shared across environments rather than isolated to this project, complicating reproducibility and increasing the effect of package replacement or unintended upgrades.

Attack Path

  1. An upstream package release or configured package source becomes compromised, or an unsafe release is published.
  2. A user follows the documented command:
    bash
    pip install --user opendataloader-pdf
    
  3. pip installs the currently selected package release without verification against a project-controlled version and hash.
  4. Malicious package installation logic may execute during installation.
  5. Malicious runtime logic may also execute when scripts/pdf_extractor.py imports opendataloader_pdf.
  6. The dependency code runs with the permissions and data access of the user operating the skill.

Impact Assessment

A compromised dependency can potentially execute arbitrary c ...[truncated 457 chars]

Remediation
View remediation

Remediation Suggestions

Pin the dependency to a specifically reviewed version and verify its distribution hash. For example, maintain a requirements file generated with trusted hashes:

text
opendataloader-pdf==REVIEWED_VERSION \
    --hash=sha256:REVIEWED_DISTRIBUTION_HASH

Install dependencies with hash enforcement:

bash
python -m pip install --require-hashes -r requirements.txt

Further hardening should include:

  • Installing into a project-specific virtual environment rather than the shared user site.
  • Explicitly configuring and documenting the trusted package index.
  • Reviewing transitive dependencies and pinning them through a lock file.
  • Running dependency vulnerability and provenance checks in continuous integration.
  • Updating pins only after reviewing and testing the new release.
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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)

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code validates the input path against workspace traversal but performs no comparable validation on output_dir before passing it to the PDF conversion library. An attacker or untrusted caller can direct writes to arbitrary filesystem locations accessible to the process, which can overwrite files, place generated content in sensitive directories, or bypass workspace containment assumptions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code invokes a conversion routine that produces output in output_dir, which is a file-writing operation. Although there is a progress print statement, there is no explicit warning in comments or docstrings that the skill will create or modify files in the specified directory.

Content

No source excerpt is available for this finding.