Back to skill

Security audit

PDF Text Replace

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real PDF text-editing tool, but it needs review because encrypted PDFs, passwords, and document excerpts can be left exposed on disk or in process arguments.

Install only if you are comfortable using it on local PDFs with sensitive-document precautions. Avoid processing confidential or encrypted PDFs unless you can control temporary files, clean up /tmp afterward, and accept that password-protected documents may be written out decrypted unless explicitly re-encrypted.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pdf_text_replace.py:541
Finding

Predictable Shared Temporary Paths Expose Decrypted PDF Content

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pdf_text_replace_v2_advanced.py:568
Finding

PDF Password Exposed Through qpdf Process Arguments

Content
View full analysis
`. Although the subprocess is invoked with an argument list and therefore is not vulnerable to shell metacharacter injection, command-line arguments are not an appropriate transport for secrets. Depending on the operating system and process-inspection permissions, command arguments may be visible through process listings, `/proc`, endpoint monitoring, crash diagnostics, audit logs, or administrative tooling. The password remains observable for the lifetime of the qpdf process. ### Attack Path 1. A victim invokes `open_pdf_smart()` with a password-protected PDF. 2. The pypdf and pikepdf strategies fail or are unavailable, causing the qpdf fallback to run. 3. The Skill starts qpdf with the password in its process argument list. 4. A local attacker or monitoring process inspects the qpdf command line while it is running. 5. The attacker extracts the value following `--password=` and uses it to open the protected PDF or any other resource that reuses the password. ### Impact Assessment The vulnerability can disclose the supplied PDF password to another local user with sufficient process-inspection access or to host-level monitoring systems. The exposed password grants access to the protected document and may have broader impact if the user reused it elsewhere. This issue does not itself provide remote code execution or privilege escalation. ]]>
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pdf_text_replace_v2_advanced.py:568
Finding

Successful qpdf Decryption Leaves a Plaintext Temporary PDF Behind

Content
View full analysis
temp file '{tmp_path}'") print(f"[open_pdf_smart] NOTE: Temp file must be cleaned up by caller: {tmp_path}") return reader, "qpdf", True ``` ### Technical Analysis `tempfile.mkstemp()` securely creates an unpredictable file, but the successful qpdf path returns a `PdfReader` without deleting the plaintext file. Cleanup occurs only on qpdf failure elsewhere in the function. The return value does not include the temporary path or a cleanup callback. Merely printing the path does not give callers a reliable lifecycle mechanism. Consequently, callers can easily leave decrypted documents in temporary storage. This is distinct from the predictable-path issue in the main entry point: the filename here is unpredictable, but the sensitive-data retention problem remains. ### Attack Path 1. A caller opens an encrypted PDF through `open_pdf_smart()`. 2. Earlier decryption strategies fail, so the qpdf fallback decrypts the document to a temporary file. 3. qpdf succeeds and the function returns a `PdfReader`. 4. The caller has no structured cleanup handle and does not remove the temporary file. 5. The plaintext document remains in the temporary directory after processing. 6. A local actor with suitable filesystem access, a backup process, forensic tooling, or later code running under the same account obtains the decrypted content. ### Impact Assessment The complete plaintext ...[truncated 367 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
SKILL.md:13
Finding

Third-Party Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description promises a PDF text-replacement tool with broad capabilities across many PDF types and editing scenarios. The supplied code chunk instead only creates a demo/sample PDF certificate for testing, with carefully placed text and embedded fonts to facilitate another tool's operation. Its primary purpose is PDF generation, not PDF modification. There is no logic for reading PDFs, locating target text, replacing content, preserving original layout during replacement, decrypting PDFs, performing OCR, or handling arbitrary user-requested changes. This is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The description is broader than the supplied code. The code genuinely supports some declared areas: PDF text replacement, custom font/CMap decoding, variable-length replacements to a limited extent, and encrypted PDF handling with multiple fallback strategies. However, several prominent claims are not represented in the code chunk. There is no OCR pipeline or image processing for scanned PDFs, no logic for modifying styles, and no comprehensive handling proving support for 'any PDF.' Replacement is limited to parsed Tj/TJ stream operations and depends on available font mappings; many PDFs use other representations or more complex layouts. Therefore the declared description materially overstates the actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code substantially matches part of the description: it does support variable-length replacement and style changes, and it includes limited embedded font subset creation when replacement characters are missing. However, the declared purpose is broader than the actual implementation. There is no code for decrypting/opening encrypted PDFs, no OCR or image-analysis pipeline for scanned PDFs, and no end-to-end handling of arbitrary PDFs. Instead, the module exposes helper functions that manipulate already-decoded PDF text streams and depend on caller-supplied font mappings. Therefore the description overstates the capability and universality of the implementation.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code does perform PDF text replacement, but only through an OCR-and-raster workflow aimed at scanned/image-based PDFs. It does not implement native text-object editing for standard vector PDFs, nor the advanced capabilities claimed in the description such as custom font encoding handling, embedded subset decoding, robust encrypted-PDF handling, high-fidelity preservation, or generalized style/layout-aware replacement. The description overstates breadth and fidelity: this script is a specialized OCR replacement tool, not a comprehensive 'replace text in any PDF' solution.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The code does perform PDF text replacement, so it is related to the declared purpose, but the description substantially overstates its scope and robustness. The implementation is a specialized stream-level replacer for Tj/TJ operations on a selected page. It parses Tm/Tf and text drawing operators, optionally decodes bytes using ToUnicode CMaps, and substitutes text if it can encode the replacement back into the font mapping or latin-1. There is no OCR pipeline, no image processing, no encrypted PDF logic, no general style editing, and no evidence of comprehensive handling for arbitrary custom encodings beyond simple ToUnicode extraction. It also may reduce multiple operations to a single Tj, which does not guarantee preserved visual fidelity. Therefore the description is materially broader than the actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises a comprehensive PDF text replacement tool that can modify specific text in essentially any PDF, including difficult cases such as custom encodings, embedded subsets, encrypted files, scanned/OCR PDFs, and variable-length replacements. This code chunk is much narrower: it is a style-overlay helper that finds existing visible text on one page, whites it out, and redraws the same text with optional styling changes. Its primary purpose is styling, not content replacement. It lacks any logic for OCR, font-encoding recovery, replacement with different text, handling variable-length substitutions, or broad encrypted-PDF workflows. Therefore the code materially under-delivers relative to the declared purpose, so this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The declared description promises a broad, high-fidelity PDF text replacement capability across many PDF types and complexities, including encoded text, embedded subset fonts, encrypted PDFs, OCR scans, variable-length replacements, and style changes. The supplied code chunk is much narrower: it is explicitly an OCR module for image-based PDFs. It detects whether a page seems image-based, rasterizes the page, OCRs visible text, removes matched regions by inpainting, redraws replacement text with PIL, and replaces the PDF page content with the resulting image. This supports one slice of the declared functionality—OCR-based replacement for scanned/image pages—but does not implement the broader PDF text editing features claimed. In particular, there is no code for parsing/editing native PDF text objects, handling custom encodings or embedded subset fonts, decrypting encrypted PDFs, preserving original typography/styles, or robustly accommodating variable-length replacements. Because the actual behavior is materially narrower and different from the declared all-purpose PDF text replacement description, this is a mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares capabilities that imply reading, writing, and invoking shell commands, but it does not define any explicit tool scope or permission boundaries. In an agent environment, that increases the chance of over-broad filesystem access or unintended command execution against user-provided PDF paths and related resources.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill explicitly encourages modification of certificates, contracts, and encrypted PDFs, including password handling, without a clear warning about legal sensitivity, confidentiality, or secret exposure. In an agent setting, that increases the chance users paste passwords into prompts or use the tool on sensitive documents without understanding the privacy and integrity consequences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code writes a cropped verification image derived from the processed PDF to a fixed path in /tmp, which can expose potentially sensitive document content on disk without the caller’s explicit consent. Using a predictable filename also increases the chance of unintended disclosure, overwrites, or symlink-based file redirection in shared environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

During qpdf fallback, the code decrypts the PDF into a temporary file on disk and explicitly leaves cleanup to the caller. This can expose sensitive document contents in plaintext to other local users, backups, forensic recovery, or later accidental disclosure, especially because the function is designed to handle encrypted PDFs where confidentiality is expected.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/pdf_text_replace_v2_advanced.py (reported line 574)May include surrounding context.

python
if password:
                cmd += [f"--password={password}"]
            cmd += [path, tmp_path]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            if result.returncode == 0:
                reader = PdfReader(tmp_path)
                print(f"[open_pdf_smart] Decrypted with qpdf subprocess -> temp file '{tmp_path}'")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/pdf_text_replace_v2_advanced.py (reported line 610)May include surrounding context.

python
return p
    # Try PATH
    try:
        result = subprocess.run(["which", "qpdf"], capture_output=True, text=True, timeout=5)
        if result.returncode == 0:
            return result.stdout.strip()
    except Exception:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The save path defaults to re_encrypt=False, and the implementation states that output will be unencrypted/decrypted in that case. In a skill whose purpose includes opening encrypted PDFs transparently, this creates a meaningful confidentiality risk: users may modify a protected document and unknowingly write a plaintext version to disk, defeating the original protection model.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The docstring for replace_page_image says it will 'Replace a page's image content in the PDF,' which implies preserving the rest of the PDF. However, the reportlab fallback path delegates to logic that, when pypdf is unavailable, simply copies a single-page overlay PDF to the output, losing all other pages. This is an active contradiction between the documented behavior and actual behavior in that execution path.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The inline comments state 'Clear existing content and insert new image' and 'Use insert_image which replaces the entire page with the image.' In reality, page.clean_contents() normalizes content streams but does not guarantee complete removal of all existing page objects, and insert_image adds an image to the page rather than semantically replacing the page contents. The comments overstate what the code guarantees.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This Python file contains natural-language documentation and user-facing print strings entirely in Chinese, and the interface does not provide any language or locale opt-in. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless the locale restriction is clearly justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function saves changes directly back to the original PDF path using incremental in-place update semantics, with no backup creation, alternate output path, or confirmation mechanism in this code path. In a text-replacement skill, this can cause irreversible corruption or unintended modification of user documents if the wrong file, page, or match set is targeted, especially when processing encrypted or complex PDFs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The primary title and descriptive content are written in Chinese, and the file does not indicate that other languages are supported or that the user may choose their preferred language. This is a natural-language policy concern because it imposes a specific language without opt-in or documented justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This code performs a file write to the caller-supplied output path, which can overwrite or create a PDF on disk. Although the function docstring says the result is written to output_path, there is no runtime confirmation prompt or explicit user-facing warning at the point of the write.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code hard-codes a default OCR language setting of "chi_sim+eng", which imposes a specific language/locale behavior on users unless they explicitly override it. This is a natural-language policy concern because the skill chooses language handling by default rather than prompting for or documenting a user preference.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The main replacement pipeline exposes a default language parameter of "chi_sim+eng", which means the skill's primary behavior assumes a specific language set without explicit user choice. Because this is part of the top-level API, the locale preference is embedded in normal operation rather than being opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.