Back to skill

Security audit

Book PDF to Structured JSON

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a legitimate book-conversion tool, but a filename validation flaw can write output files outside the chosen folder, so it should be reviewed before installation.

Review before installing. Use only simple book IDs made from letters, numbers, dots, underscores, or hyphens, and point outputs to a dedicated versioned folder. Do not pass untrusted `book-id` values, and do not perform upload or replacement unless the target environment, backup, credentials handling, and read-back export are explicitly approved.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/convert_book.py:738
Finding

Path Traversal Through an Unvalidated Book Identifier

Content
View full analysis
None: fields = [ "candidate_id", "book_id", "node_key", "original", "suggestion", "context", "decision", "reviewer", ] path.parent.mkdir(parents=True, exist_ok=True) with path.open("w", encoding="utf-8", newline="") as handle: writer = csv.DictWriter( handle, fieldnames=fields, delimiter="\t", lineterminator="\n", ) writer.writeheader() writer.writerows(rows) ``` ### Technical Analysis The `--book-id` command-line value is accepted without character or path validation and is interpolated directly into output filenames. Python's `pathlib` does not confine the resulting path to `args.output_dir`. A value containing traversal components, such as `../../target`, causes the generated ledger and canonical JSON paths to resolve outside the int ...[truncated 2426 chars]
Remediation
View remediation
Path: resolved_root = root.resolve() destination = (resolved_root / filename).resolve() if not destination.is_relative_to(resolved_root): raise ValueError(f"output path escapes output directory: {destination}") return destination ``` Use this helper for both destinations: ```python ledger_path = confined_path( args.output_dir, f"{args.book_id}_ocr-review.tsv", ) canonical = confined_path( args.output_dir, f"{args.book_id}_tree.json", ) ``` 4. Where supported, account for symlink races by opening files relative to a trusted directory descriptor and using operating-system protections such as `O_NOFOLLOW`. At minimum, reject symlinked output directories or destination files before replacement. 5. Avoid creating parent directories from attacker-derived paths. Create the approved output directory once, then require all generated files to be direct children or explicitly validated descendants. 6. Add regression tests covering: - `../` and nested traversal sequences. - Absolute POSIX paths. - Windows drive and UNC paths. - Forward and backward separators. - NUL and control characters. - Symlinked ...[truncated 186 chars]
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broad, end-to-end book extraction/rebuilding system operating on raw source documents and including OCR, TOC reconstruction, validation, upload, backup, and verification. This code chunk is much narrower: it is a derivative builder for already-existing canonical book-tree JSON. Its primary purpose is to render text/TSV outputs from structured JSON and copy the canonical JSON into an output directory. While some outputs mentioned in the description overlap partially (per-chapter TXT, combined TXT, TSV), the major declared capabilities are absent, and the actual code depends on prebuilt canonical JSON rather than converting source books. Therefore the description materially overstates and misrepresents what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description promises a large ingestion/transformation workflow for rebuilding complete books from source documents, including OCR, text extraction, hierarchical edition construction, output generation, upload, backup, and verification. The actual code does none of that. It only compares already-produced local book tree JSON files against a remote export, checking titles, node structures/content, and hashes, then emits TSV status lines. While this could be one small validation component within a larger pipeline, the chunk’s primary purpose is materially different from the declared end-to-end conversion/rebuild capability. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code substantially matches the core declared purpose around whole-book extraction, OCR fallback, printed-TOC reconstruction, OCR review handling, hierarchical JSON generation, and deterministic validation. However, the declared description includes additional concrete end-to-end capabilities that are not present in this code chunk: there is no network/API interaction for upload, no backup logic, and no read-back verification after upload. Also, while the script invokes build_one() which may generate derivative outputs, this chunk itself only clearly writes canonical JSON, page text files, a TOC draft, manifest, validation log, and OCR review TSV; per-chapter TXT and combined TXT are not directly implemented here. Because the declared description presents a broader pipeline than this supplied code actually performs, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The declared description presents a comprehensive pipeline that converts source documents into a publication-grade electronic edition, including extraction/rebuilding, OCR cleanup workflow, structured outputs, upload, backup, and verification. The supplied code chunk does not implement that pipeline. Instead, it narrowly performs validation of already-produced canonical tree JSON and derivative artifacts, checks OCR review ledger completeness/resolution, emits fingerprints, and optionally launches a remote comparison script. Some listed features are adjacent—deterministic validation and read-back verification are partially represented—but the primary purpose is materially different from conversion/rebuilding. Because major claimed capabilities are absent from the code chunk, while the actual code is a validator/auditor, the description does not accurately represent this chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Use [scripts/convert_book.py](scripts/convert_book.py) as the primary one-book entry point. It extracts PDF/DOCX/TXT sources, falls back to page OCR for weak

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Use [scripts/convert_book.py](scripts/convert_book.py) as the primary one-book entry point. It extracts PDF/DOCX/TXT sources, falls back to page OCR for weak

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Use [scripts/convert_book.py](scripts/convert_book.py) as the primary one-book entry point. It extracts PDF/DOCX/TXT sources, falls back to page OCR for weak

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill text directs use of file read/write, shell execution, and optional networked upload/verification behavior, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates an authorization ambiguity where an agent may invoke broader capabilities than a reviewer or runtime policy expects, increasing the risk of unintended filesystem access, command execution, or remote mutation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill allows implicit invocation with no documented trigger constraints, exclusions, or user-confirmation requirements. Because this skill can process and transform whole-book documents and perform upload/verification workflows, automatic invocation could cause unintended handling of large or sensitive files, or trigger higher-risk downstream actions without clear user intent.

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/convert_book.py (reported line 67)May include surrounding context.

python
def run(command: list[str], *, timeout: int | None = None) -> subprocess.CompletedProcess[str]:
    return subprocess.run(command, text=True, capture_output=True, check=False, timeout=timeout)


def require_command(name: str) -> str:

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/convert_book.py (reported line 799)May include surrounding context.

python
str(args.min_heading_score),
            "--fail-on-warnings",
        ]
        validation = subprocess.run(command, text=True, capture_output=True, check=False)
        (work_dir / "validation.log").write_text(validation.stdout + validation.stderr, encoding="utf-8")
        if validation.stdout:
            print(validation.stdout, end="")

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/test_bundle_tools.py (reported line 72)May include surrounding context.

python
self.temporary.cleanup()

    def run_tool(self, *arguments: object) -> subprocess.CompletedProcess[str]:
        return subprocess.run(
            [sys.executable, *(str(item) for item in arguments)],
            text=True,
            capture_output=True,

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/validate_bundle.py (reported line 268)May include surrounding context.

python
def compare_remote(local_dir: Path, remote_export: Path, audit: Audit) -> None:
    comparator = Path(__file__).with_name("compare_tree_export.py")
    result = subprocess.run(
        [sys.executable, str(comparator), "--local-dir", str(local_dir), "--remote-export", str(remote_export)],
        text=True,
        capture_output=True,

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The file presents the skill name and description in Chinese while the default prompt is fixed in English. This can impose a language behavior without user opt-in or explanation, which may conflict with language or locale policy expectations.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.