Back to skill

Security audit

PDF Converter

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed PDF/image conversion wrapper, but it depends on ComPDF downloads, a proprietary SDK, and local trial-usage tracking.

Before installing, decide whether you are comfortable running a proprietary PDF conversion SDK on your documents, allowing first-run downloads from ComPDF, and storing a trial usage counter locally. For sensitive PDFs, use an isolated environment, pre-provision the license and model files, and consider pinning or otherwise validating the SDK and model version.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T08 · Insecure Dependencies

Error
Location
SKILL.md:33
Finding
Unpinned Proprietary Python Dependency<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:33-37` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: High ### Vulnerable Code ```markdown ## Prerequisites - Supports Windows and macOS. - The conversion SDK must be installed first: ```bash pip install ComPDFKitConversion ``` ``` ### Technical Analysis The installation command retrieves the latest available `ComPDFKitConversion` release without specifying an audited version or requiring package hashes. The conversion script then imports and invokes this proprietary dependency directly. Because the effective dependency content can change independently of the reviewed Skill, a compromised package release, package registry account, or distribution channel could introduce malicious Python or native code. The package's internal behavior cannot be verified from the project files. No evidence shows that the current package is malicious. The vulnerability is the absence of version and artifact integrity controls. ### Attack Path 1. An attacker compromises the package publisher account, package distribution infrastructure, or a future package release. 2. The attacker publishes a modified `ComPDFKitConversion` artifact under the expected package name. 3. A user follows the documented `pip install ComPDFKitConversion` command. 4. Pip installs the unreviewed release without checking a project-provided version constraint or cryptographic hash. 5. The malicious component executes when the conversion script imports or calls the SDK. ### Impact Assessment A malicious dependency would execute with the privileges of the user running the Skill. It could potentially: - Read or modify files accessible to that user. - Access PDF and image documents submitted for conversion. - Access PDF passwords passed to the SDK. - Read environment variables and user-level credentials. - Initiate arbitrary network connections. - Alter generated conversion output. No operating-system privile ...[truncated 152 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the dependency to a specifically reviewed version, for example: ```bash python -m pip install "ComPDFKitConversion==<audited-version>" ``` 2. Distribute a locked requirements file containing SHA-256 hashes and install it with: ```bash python -m pip install --require-hashes -r requirements.txt ``` 3. Obtain expected hashes from a separately authenticated source and verify each platform-specific wheel. 4. Review new SDK versions before updating the lock file. 5. Install the SDK in an isolated virtual environment with only the permissions required for conversion. 6. Where sensitive documents are processed, apply outbound network restrictions to the conversion process. 7. Document the exact supported SDK version rather than treating the latest locally installable wheel as authoritative. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/pdf-convert-compdf.py:316
Finding
Downloaded AI Model Is Loaded Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pdf-convert-compdf.py:136, 316-355, 530-543` **Vulnerability Type**: Unverified externally supplied component **Risk Level**: Medium ### Vulnerable Code ```python DOCUMENT_AI_MODEL_URL = "https://download.compdf.com/skills/model/documentai.model" DOCUMENT_AI_MODEL_ENV = "COMPDF_DOCUMENT_AI_MODEL" DOCUMENT_AI_MODEL_RETRY_DELAYS = (2, 5, 10) ``` ```python def download_file(url: str, destination: Path, timeout: int = 120) -> None: destination.parent.mkdir(parents=True, exist_ok=True) with urllib.request.urlopen(url, timeout=timeout) as response, destination.open("wb") as output: while True: chunk = response.read(1024 * 1024) if not chunk: break output.write(chunk) ``` ```python def ensure_document_ai_model(scripts_dir: Path) -> Path: model_path = get_document_ai_model_path(scripts_dir) if model_path.is_file() and model_path.stat().st_size > 0: return model_path temp_path = model_path.with_suffix(model_path.suffix + ".part") last_error: Exception | None = None for attempt in range(len(DOCUMENT_AI_MODEL_RETRY_DELAYS) + 1): try: print(f"documentai.model not found, downloading from {DOCUMENT_AI_MODEL_URL}...", file=sys.stderr) if temp_path.exists(): temp_path.unlink() download_file(DOCUMENT_AI_MODEL_URL, temp_path) if not temp_path.is_file() or temp_path.stat().st_size == 0: raise RuntimeError("Downloaded documentai.model is empty") temp_path.replace(model_path) break except Exception as exc: last_error = exc if temp_path.exists(): temp_path.unlink() if attempt >= len(DOCUMENT_AI_MODEL_RETRY_DELAYS): raise RuntimeError(f"Failed to prepare documentai.model: {exc}") from exc time.sleep(DOCUMENT_AI_MODEL_RETRY_DELA ...[truncated 3083 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Publish a trusted SHA-256 digest or digital signature for every supported model version. 2. Verify the downloaded temporary file before renaming or loading it: ```python EXPECTED_MODEL_SHA256 = "<trusted-sha256>" def verify_sha256(path: Path, expected: str) -> None: digest = hashlib.sha256() with path.open("rb") as stream: for chunk in iter(lambda: stream.read(1024 * 1024), b""): digest.update(chunk) if digest.hexdigest() != expected: raise RuntimeError("documentai.model integrity verification failed") ``` 3. Perform verification immediately after download and delete the temporary file on mismatch. 4. Verify existing cached models before reuse rather than checking only their size. 5. Apply equivalent validation to paths supplied through `COMPDF_DOCUMENT_AI_MODEL`. 6. Pin the model to an explicit version and use a version-specific URL rather than a mutable generic path. 7. Make automatic model downloading opt-in, or clearly request user approval before the first download. 8. Run native model parsing in a sandbox with restricted filesystem and network access where sensitive documents are processed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The manifest and description materially understate behavior: the skill performs remote downloads, local license enforcement, trial tracking, supports image input, and does not match the advertised XML capability. This mismatch can mislead operators into approving a skill they believe is local-only PDF conversion when it actually reaches out to third-party servers and changes local state.

Ae1

High
Category
analysis-evasion
Content
- The entry point is `SKILL.md`; helper scripts are placed in `scripts/`.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares no explicit tool scope despite clearly requiring network, file read/write, and environment access. In agent environments, missing permission boundaries increases the chance the skill is invoked with broader capabilities than users expect, enabling silent downloads and filesystem changes.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
Automatic downloads of `license.xml` and a large model file introduce supply-chain and privacy risks because execution depends on fetching remote content at runtime. Even if intended for product functionality, this expands trust to external infrastructure and can cause unexpected network egress and disk writes in supposedly local workflows.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation acknowledges automatic downloads and file creation but does not present them as prominent privacy/system-impact warnings. In practice, users may run the skill expecting offline local conversion and unknowingly trigger network egress, large downloads, and persistent files, which is risky in restricted or sensitive environments.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The script automatically downloads a license file and Document AI model from remote servers during normal conversion flow, even though the skill presents itself primarily as a local PDF conversion tool. This creates an unannounced network dependency and supply-chain trust boundary: a compromised server, redirected traffic, or unexpected remote content could alter tool behavior or introduce malicious artifacts the local process will then trust.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The tool performs automatic remote downloads without clear upfront disclosure in the CLI interface, so users invoking a local conversion command may unknowingly trigger network access and external file retrieval. This weakens informed consent and increases exposure to supply-chain, privacy, and policy-compliance risks, especially in restricted or offline environments.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill writes persistent usage-tracking data into the user's home directory for license enforcement, which exceeds the minimal scope expected for a one-shot file conversion utility. While not an immediate code-execution risk, it creates undisclosed statefulness, possible privacy concerns, and potential interference with multi-user or automated environments where hidden home-directory writes are undesirable.

Scope Creep

Low
Category
Excessive Agency
Content
------------------------------------------------------------------------

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

IN NO EVENT SHALL PDF TECHNOLOGIES, INC. OR ITS AFFILIATES BE LIABLE FOR
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Context-Inappropriate Capability

Low
Confidence
84% confidence
Finding
These lines describe behavior beyond conversion itself: fingerprinting the license type, counting conversions, refusing service after a threshold, and directing users to a purchase URL. That licensing/marketing enforcement capability is not part of the manifest's stated purpose of converting PDFs for LLM processing.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
def resolve_converter(format_name: str):
    method_name = get_converter_method_name(format_name)
    converter = getattr(CPDFConversion, method_name, None)
    if converter is None:
        raise RuntimeError(f"Current SDK does not provide converter method: {method_name}")
    return converter
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.