Back to skill

Security audit

pdf2ofd

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward PDF-to-OFD converter, but users should treat its document parsing dependencies and large-file handling as operational risks.

Install and run this in an isolated environment, pin and review dependencies before production use, and only convert PDFs you intentionally select. Do not expose it as an upload-facing service unless you add strict input size, page count, image, memory, disk, runtime, and concurrency limits.

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)

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Unpinned and Unnecessary Third-Party Dependencies## Vulnerability Details **File Location**: `requirements.txt:1-6` **Vulnerability Type**: `T08: Insecure Dependencies` **Risk Level**: Medium ### Vulnerable Code ```text easyofd PyMuPDF Pillow reportlab xmltodict loguru ``` ### Technical Analysis Every Python dependency is specified without an exact version or an integrity hash. Consequently, separate installations can resolve to different package versions, and future releases will be trusted without being reviewed by this project. In addition, `reportlab`, `xmltodict`, and `loguru` are not imported directly by `pdf2ofd.py`. Unless they are required for an external integration not present in the audited project, retaining these packages unnecessarily expands the dependency and installation attack surface. No evidence was found that any currently named dependency is malicious. The security issue is the lack of dependency version and integrity controls, not a confirmed compromise of a particular package. ### Attack Path 1. An attacker compromises an upstream dependency account, distribution artifact, or release process. 2. The attacker publishes a malicious version under one of the dependency names in `requirements.txt`. 3. A user or deployment pipeline executes `pip install -r requirements.txt`. 4. Because no exact version or hash is required, the package resolver may select the malicious release. 5. Malicious installation or runtime code executes with the permissions of the installing or converter process. ### Impact Assessment Successful exploitation through a compromised dependency could permit arbitrary code execution with the privileges of the account installing or running the converter. Depending on its deployment context, this could expose local files, input documents, output documents, environment variables, and credentials accessible to that account. This issue does not independently provide privilege escalation. Its scope is bounded by the pe ...[truncated 89 chars]
Remediation
## Remediation Suggestions 1. Remove direct dependencies that are not required by the application. Confirm whether `reportlab`, `xmltodict`, and `loguru` are needed transitively or by an undocumented integration before retaining them. 2. Pin every direct and transitive dependency to an exact, reviewed version. 3. Generate a reproducible lock file with cryptographic hashes, such as a hash-locked requirements file produced by `pip-tools`. 4. Install dependencies with hash verification, for example through `pip install --require-hashes`. 5. Use a private or controlled package index where appropriate and explicitly configure trusted package sources. 6. Scan locked dependencies for known vulnerabilities in CI and review updates before merging them. 7. Build and execute the converter in a minimally privileged, isolated environment so that a dependency compromise has limited impact.

T09 · Insecure Skill Coding Practices

Warning
Location
pdf2ofd.py:70
Finding
Unbounded Processing of Untrusted PDF Content Can Exhaust Resources## Vulnerability Details **File Location**: `pdf2ofd.py:70-158, 254-264, 299-307` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Medium ### Vulnerable Code Input parsing and image expansion occur without resource limits: ```python def patched_extract(self, doc_byte): res_map = {"img": {}, "font": {}, "other": {"page_size": []}} details = [] with fitz.open(stream=doc_byte, filetype="pdf") as doc: for page in doc: res_map["other"]["page_size"].append(list(page.rect)) page_data = [] # Text for block in page.get_text("rawdict").get("blocks", []): if block.get("type") == 0: for l in block["lines"]: for s in l["spans"]: chars = s.get("chars", []) text = "".join([c["c"] for c in chars]) ``` ```python # Images for img in page.get_images(full=True): xref, smask_xref = img[0], img[1] res_uid = f"IMG_{xref}" try: pix = fitz.Pixmap(doc, xref) if smask_xref > 0: pix = fitz.Pixmap(pix, fitz.Pixmap(doc, smask_xref)) if pix.colorspace and pix.colorspace.n not in (3, 4): pix = fitz.Pixmap(fitz.csRGB, pix) buf = io.BytesIO() if pix.alpha: Image.frombytes("RGBA", [pix.width, pix.height], pix.samples).save(buf, format="PNG") ext = "png" else: Image.frombytes("RGB", [pix.width, pix.height], pix.samples).save(buf, format="JPEG") ext = "jpg" res_map["img"][res_uid] = (buf, ext) for r in page.get_image_rects(xref): if r: page_data.append({"type": "img", "bbox": list(r), "res_uuid": res_uid}) except: pass ``` Generated resources and the ZIP output are also accumulated in memory: ```python for k, v in self.res_static.items(): with ope ...[truncated 2937 chars]
Remediation
## Remediation Suggestions 1. Reject inputs exceeding a documented maximum byte size before reading the complete file. 2. Inspect PDF metadata and enforce maximum page, image, drawing-object, and text-element counts. 3. Validate image dimensions before materializing pixel buffers and enforce per-image and aggregate decoded-pixel limits. 4. Set hard conversion time, memory, CPU, temporary disk, and output-size limits at the worker or container level. 5. Limit conversion concurrency and apply per-user rate limits when the converter is exposed through an upload service. 6. Stream input and output where supported instead of retaining the original PDF, all decoded resources, and the final OFD archive in memory simultaneously. 7. Abort cleanly when a limit is reached and remove partially generated output. 8. Replace `except: pass` with narrow exception handlers, log failures without exposing sensitive document contents, and reject documents when required resources cannot be processed safely. 9. Keep PyMuPDF and Pillow on reviewed, supported versions because they parse complex attacker-controlled formats. 10. Run conversion in a sandboxed, minimally privileged worker with no network access and a dedicated temporary directory subject to a strict quota.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (12)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises direct execution of a Python script that reads an input PDF and writes an output OFD, but it does not declare any tool scope or permissions governing file access. In an agent environment, undeclared file_read/file_write capability creates a mismatch between documented behavior and enforcement, increasing the risk of unintended file access or output creation without explicit sandboxing expectations.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger phrase "When a user asks to convert a PDF or a 'High-Fidelity' invoice to OFD" is broad enough that the skill may activate for generic document-conversion requests without strong confirmation of user intent. In a system with file-handling abilities, overbroad invocation can cause the wrong skill to process sensitive documents or perform writes unexpectedly.

Unpinned Dependencies

Low
Category
Supply Chain
Content
easyofd
PyMuPDF
Pillow
reportlab
Confidence
98% confidence
Finding
The dependency easyofd is unpinned, so builds may resolve to different versions over time, creating supply-chain risk and making security reviews non-reproducible. In a document-conversion skill that processes untrusted files, unexpected dependency upgrades can silently introduce vulnerable or malicious code paths.

Unpinned Dependencies

Low
Category
Supply Chain
Content
easyofd
PyMuPDF
Pillow
reportlab
xmltodict
Confidence
99% confidence
Finding
PyMuPDF is unpinned, which makes the installed version unpredictable and prevents determining whether known flaws are present. Because this skill converts PDFs, PyMuPDF is directly exposed to attacker-controlled document input, increasing the risk that a vulnerable release could be exploited.

Unverifiable Dependency: PyMuPDF has 2 known advisory(ies) (CVE-2026-3029 (PyMuPDF has a path traversal in _main_.py); CVE-2026-3029 (PyMuPDF has a path traversal in _main_.py)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding
PyMuPDF has known advisories, but because no version is pinned, it is impossible to verify whether deployments are safe. This is more dangerous in this skill because PyMuPDF is central to processing potentially untrusted PDF inputs, so an affected version could be directly reachable by attackers.

Unpinned Dependencies

Low
Category
Supply Chain
Content
easyofd
PyMuPDF
Pillow
reportlab
xmltodict
loguru
Confidence
99% confidence
Finding
Pillow is unpinned, so deployments may pull different releases, including versions with known security issues. Since document conversion often involves rendering embedded images from untrusted files, a vulnerable Pillow release could expose the service to code execution, crashes, or resource exhaustion.

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
99% confidence
Finding
Pillow has multiple known advisories, including code execution and denial-of-service issues, and the unpinned requirement prevents verifying whether a safe release is installed. Because the skill likely handles attacker-supplied images embedded in PDFs or related assets, this uncertainty creates meaningful exploit risk.

Unpinned Dependencies

Low
Category
Supply Chain
Content
easyofd
PyMuPDF
Pillow
reportlab
xmltodict
loguru
Confidence
99% confidence
Finding
ReportLab is unpinned, leaving the build open to unexpected versions, including releases with historical RCE and SSRF issues. In a PDF/OFD conversion workflow, this library may process document content or generate output from attacker-influenced data, so version drift materially raises risk.

Unverifiable Dependency: reportlab has 8 known advisory(ies) (CVE-2023-33733 (Reportlab vulnerable to remote code execution); CVE-2020-28463 (Server-side Request Forgery (SSRF) via img tags in reportlab); CVE-2019-19450 (ReportLab vulnerable to remote code execution via paraparser) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
99% confidence
Finding
ReportLab has several serious historical advisories, including remote code execution and SSRF, and the missing version pin means the installation may resolve to an affected release. In a document-conversion context that may transform or generate structured document content from untrusted sources, this uncertainty substantially increases attack surface.

Unpinned Dependencies

Low
Category
Supply Chain
Content
PyMuPDF
Pillow
reportlab
xmltodict
loguru
Confidence
96% confidence
Finding
xmltodict is unpinned, which weakens build reproducibility and may allow vulnerable or incompatible releases to be installed later. Although the risk is lower than parser/rendering libraries directly handling complex binary formats, XML processing still warrants controlled versions in a conversion toolchain.

Unpinned Dependencies

Low
Category
Supply Chain
Content
Pillow
reportlab
xmltodict
loguru
Confidence
96% confidence
Finding
loguru is unpinned, so future installs may unexpectedly include a release with security or logging-behavior regressions. While logging libraries are usually less exposed than file parsers, uncontrolled version changes can still affect sensitive-data handling and operational security.

Unverifiable Dependency: loguru has 2 known advisory(ies) (CVE-2022-0338 (loguru logs sensitive information); CVE-2022-0338 (Improper Privilege Management in Conda loguru prior to 0.5.3.)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding
loguru has known advisories and the absence of version pinning makes it impossible to establish whether the deployed package is affected. The direct exploitability is lower than parser libraries, but vulnerable logging behavior can still leak sensitive document data or weaken operational controls.

Static analysis

No suspicious patterns detected.