Back to skill

Security audit

PPTX PDF Font Fix

Security checks for vulnerabilities and agentic risk

Overview

This skill locally edits PPTX files for its stated font-export workaround, with a real resource-exhaustion caution for untrusted or unusually large presentations.

Use this only on PPTX files you trust or process it in a constrained environment with file-size and runtime limits. Choose an explicit output path and avoid overwriting originals until you verify the patched presentation opens correctly.

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/fix_font_transparency.py:119
Finding
Unbounded Decompression and Parsing of Attacker-Controlled PPTX Archives<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fix_font_transparency.py`, lines 119-130 **Vulnerability Type**: Uncontrolled resource consumption through ZIP decompression **Risk Level**: Medium ### Vulnerable Code ```python for item in zin.infolist(): data = zin.read(item.filename) if (item.filename.startswith("ppt/slides/slide") and item.filename.endswith(".xml")): stats["slides_total"] += 1 new_data, count = process_slide_xml(data, transparency_pct) if count > 0: stats["slides_modified"] += 1 stats["runs_modified"] += count data = new_data zout.writestr(item, data) ``` ### Technical Analysis A PPTX file is a ZIP archive whose members and compression properties can be controlled by the user. The script enumerates every archive member and calls `zin.read(item.filename)`, decompressing the entire member into memory before determining whether it is relevant to the transformation. The implementation does not enforce limits on: - The number of archive members - The uncompressed size of an individual member - The aggregate uncompressed archive size - The ratio between compressed and uncompressed sizes - The size of slide XML passed to `ElementTree` - The processing time or output size Consequently, a highly compressed archive member can consume substantial memory when read. A large number of members can also cause excessive CPU and I/O consumption. For matching slide entries, the decompressed XML is parsed into an in-memory element tree, further increasing memory usage. The vulnerable operation applies to every member, including media and embedded objects that the script does not need to inspect. ### Attack Path 1. An attacker creates a syntactically valid PPTX/ZIP archive containing one or more highly compressed members with very large uncompressed sizes. 2. The attacker submits the crafted PPTX for processing through the documented Skill workflow. 3. Th ...[truncated 1046 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate the archive before decompressing any member: 1. Set strict limits for archive member count, individual uncompressed size, total declared uncompressed size, and compression ratio. 2. Reject entries with invalid, negative, inconsistent, or unexpectedly large metadata. 3. Apply a separate conservative size limit to slide XML before parsing it. 4. Stream-copy unchanged archive members in bounded chunks rather than loading each member entirely into memory. 5. Process modified XML under explicit memory and execution-time limits. 6. Run the conversion in an isolated worker with operating-system memory, CPU, temporary-storage, and timeout limits. 7. Remove partial output files when validation or processing fails. Example validation logic should inspect `ZipInfo.file_size` and `ZipInfo.compress_size` before calling `read()`: ```python MAX_MEMBERS = 5000 MAX_MEMBER_SIZE = 50 * 1024 * 1024 MAX_TOTAL_SIZE = 500 * 1024 * 1024 MAX_XML_SIZE = 10 * 1024 * 1024 MAX_COMPRESSION_RATIO = 100 items = zin.infolist() if len(items) > MAX_MEMBERS: raise ValueError("Archive contains too many members") total_size = 0 for item in items: if item.file_size > MAX_MEMBER_SIZE: raise ValueError(f"Archive member is too large: {item.filename}") total_size += item.file_size if total_size > MAX_TOTAL_SIZE: raise ValueError("Archive expands beyond the permitted size") compressed_size = max(item.compress_size, 1) if item.file_size / compressed_size > MAX_COMPRESSION_RATIO: raise ValueError(f"Suspicious compression ratio: {item.filename}") is_slide = ( item.filename.startswith("ppt/slides/slide") and item.filename.endswith(".xml") ) if is_slide and item.file_size > MAX_XML_SIZE: raise ValueError(f"Slide XML is too large: {item.filename}") ``` Metadata checks should be combined with runtime resource controls because ZIP metadata alone should not be treated as a complet ...[truncated 24 chars]
Vulnerability Patterns
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill instructs the agent to modify and return user-supplied files, which is a file-write capability, but it does not declare any explicit tool scope or permission boundaries. Without an allowed-tools or permissions declaration, an agent runtime may grant broader filesystem access than intended, increasing the risk of unintended file modification or overwrite during execution.

Static analysis

No suspicious patterns detected.