T09 · Insecure Skill Coding Practices
- Location
ooxml/scripts/unpack.py:14- Finding
Unbounded Office Archive Extraction Enables Resource-Exhaustion Attacks
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This PowerPoint skill is mostly aimed at presentation work, but it includes broader Office-document processing, unsafe handling of untrusted Office files, and privileged/unpinned setup guidance that warrant review before installation.
Install only after reviewing the broader DOCX/XLSX code paths and run it in an isolated, non-admin environment. Avoid following sudo or global install commands from the agent workflow; pre-provision and pin dependencies instead. Use copies of presentations, keep backups, and treat untrusted PPTX/DOCX/XLSX files as potentially hostile until archive extraction and XML parsing are hardened.
ooxml/scripts/unpack.py:14Unbounded Office Archive Extraction Enables Resource-Exhaustion Attacks
ooxml/scripts/validation/base.py:127Untrusted OOXML Is Parsed with lxml Default Entity-Resolution Behavior
SKILL.md:475Unpinned Global Dependency Installation Creates a Mutable Supply-Chain Boundary
The declared description suggests a user-facing presentation skill focused on creating, modifying, and analyzing PowerPoint presentations. This code does not implement presentation authoring or editing features; instead, it performs a generic Office Open XML packaging task on unpacked document directories. It supports not only .pptx but also .docx and .xlsx, and its main behavior is XML condensation plus zip archive creation, with optional validation by calling LibreOffice in a subprocess. That is a materially different primary purpose from the declared presentation workflow, so this is a mismatch.
The declared description frames the skill as a presentation-focused tool for creating, editing, and analyzing .pptx files. The supplied code does not implement presentation authoring or editing features; instead, it unpacks OOXML archives and reformats internal XML files. While this could be a supporting utility for inspecting presentation internals, its actual scope is broader and materially different: it handles Word and Excel files too, and contains a Word-specific feature (RSID suggestion). That makes the code's primary purpose a generic Office XML unpack/format tool, not a presentation task skill as described.
The declared description says the skill is for presentation creation, editing, and general presentation tasks on .pptx files. The supplied code instead implements a CLI validation utility that checks unpacked Office XML files against validators. For .pptx it runs a schema validator; for .docx it runs schema and redlining validators; .xlsx is accepted by extension check but not actually supported in the match branch. This is materially different from creating or editing presentations, and it also expands beyond presentations into other Office document types. Therefore the description does not accurately represent the actual behavior.
The declared description focuses on presentation (.pptx) creation, modification, layouts, notes, and general presentation-task handling. This code chunk instead serves as a package initializer for validation components, exposing validators for DOCX, PPTX, and redlining. The module docstring explicitly says 'Validation modules for Word document processing,' which further diverges from a presentation-specific editing/creation purpose. While PPTX validation is tangentially related, the visible primary purpose here is validation infrastructure and multi-format document support, including Word/DOCX, which is materially broader and different from the declared presentation-editing scope.
This is a clear description-behavior mismatch. The declared purpose is centered on presentation (.pptx) creation, editing, and analysis, but the supplied code is specifically for validating WordprocessingML/ DOCX document structure. It uses Word namespaces, parses word/document.xml, validates Word-specific XML semantics, and compares paragraph counts in a DOCX archive. None of the shown behavior creates or edits presentations, and the primary purpose is document validation for Word files, not presentation manipulation.
The implementation is narrowly focused on schema/structural validation of PPTX internals, not on authoring or modifying presentations. While 'analysis' could loosely cover validation, the declared description emphasizes creation, editing, layouts, comments, speaker notes, and broad presentation operations. The actual code performs only backend validation checks on OOXML files and relationships. This is a materially different primary purpose and omits the code's true specialized capability.
This is a clear description-behavior mismatch. The declared purpose is broad presentation manipulation for .pptx files, but the supplied code is narrowly focused on validating redlining/tracked changes in Word documents. It operates on word/document.xml, parses WordprocessingML tags like w:ins and w:del, filters edits authored by Claude, removes those tracked changes, compares text against an original .docx, and optionally invokes git diff for diagnostics. None of this is about presentation creation, editing, layouts, comments, or speaker notes. The primary resource type, file format, and task domain are materially different.
The declared description presents a broad presentation manipulation skill covering creation, editing, layouts, comments, speaker notes, and essentially any presentation task. The supplied code instead implements a narrow analysis/extraction utility: it reads PowerPoint files, extracts text and formatting information, calculates shape positions including grouped shapes, detects overflow/overlap/manual bullet issues, and writes the results to JSON. This partially aligns with the 'analysis' portion of the description, but materially overstates the skill’s capabilities because there is no functionality for creating presentations, editing slides, changing layouts, or adding comments/speaker notes. The primary behavior is inventory/diagnostic extraction rather than full presentation creation/editing.
Referenced artifact was not completely inspected
3. Create and run a JavaScript file using the [`html2pptx.js`](scripts/html2pptx.js) library to convert HTML slides to PowerPoint and save the presentation
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
<!-- ppt/slides/slide1.xml -->
<p:sld>
<p:cSld>
<p:spTree>
This file implements validation for Word .docx tracked changes, not PowerPoint .pptx, which materially diverges from the declared skill scope. Scope mismatch is dangerous because it hides undeclared document-processing capability, expands the accessible file types and code paths under the guise of a narrower skill, and undermines trust and review assumptions. In a skill ecosystem, undeclared cross-format handling can enable unexpected data access or mutation workflows reviewers did not approve.
The trigger description is extremely broad, ending with 'or any other presentation tasks,' which can cause the skill to activate for a wide range of loosely related requests. Overbroad activation increases the chance of unintended invocation, expanding the attack surface and causing the agent to use this skill in situations where its behavior may not be appropriate or expected.
The skill instructs the agent to read files, write files, inspect environment-dependent paths, and run shell commands, yet it declares no explicit tool scope or allowed-tools boundary. That makes invocation and execution authority ambiguous, increasing the chance the skill is run with broader capabilities than necessary and enabling risky file/system operations on untrusted presentations.
The description ends with a broad trigger like 'or any other presentation tasks,' which can cause over-invocation of a skill that performs shell commands, file writes, unpacking, and document transformation. In a capability-rich agent environment, vague routing language increases the chance untrusted or unrelated tasks are funneled into this skill and executed with unnecessary power.
The skill states that all text shapes will be cleared automatically unless replacement paragraphs are provided, but the warning is embedded in operational instructions rather than presented as a strong user-impact safeguard. This can lead to silent destructive modification of presentations, causing data loss or corruption when inventories are incomplete or mappings are wrong.
The skill documentation instructs use of 'sudo apt-get install libreoffice', normalizing privileged package installation as part of the workflow. In an agent setting, root-level execution materially expands blast radius: a compromised or mistaken command can alter the host system, install unexpected software, or be abused for persistence beyond the task scope.
- **playwright**: `npm install -g playwright` (for HTML rendering in html2pptx)
- **react-icons**: `npm install -g react-icons react react-dom` (for icons)
- **sharp**: `npm install -g sharp` (for SVG rasterization and image processing)
- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion)
- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images)
- **defusedxml**: `pip install defusedxml` (for secure XML parsing)
This second privileged install instruction ('sudo apt-get install poppler-utils') has the same issue: it encourages escalation beyond least privilege during normal skill use. Because the skill already relies on shell execution, mixing presentation processing with root-capable setup commands makes the context more dangerous than a simple document tool.
- **react-icons**: `npm install -g react-icons react react-dom` (for icons)
- **sharp**: `npm install -g sharp` (for SVG rasterization and image processing)
- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion)
- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images)
- **defusedxml**: `pip install defusedxml` (for secure XML parsing)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
with tempfile.TemporaryDirectory() as temp_dir:
try:
result = subprocess.run(
[
"soffice",
"--headless",
The script extracts every entry from a user-supplied Office archive directly to disk using extractall() without validating member paths. A malicious ZIP-based Office file can exploit path traversal (Zip Slip) via filenames containing '..' or absolute paths, causing files to be written outside the intended output directory and potentially overwriting arbitrary files accessible to the user.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
modified_file.write_text(modified_text, encoding="utf-8")
# Try character-level diff first for precise differences
result = subprocess.run(
[
"git",
"diff",
The manifest describes a skill for creating, editing, and analyzing PowerPoint presentations, but this file implements Word redlining validation and shells out to git diff to compute textual differences. Spawning external processes is not an obvious or necessary capability for presentation work, and it expands the runtime capabilities beyond what the stated purpose suggests.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
return "\n".join(content_lines)
# Fallback to word-level diff if character-level is too verbose
result = subprocess.run(
[
"git",
"diff",
The function loads attacker-controlled local HTML in Playwright and forwards all browser console messages directly to the host console. Malicious HTML can intentionally emit sensitive local data, file paths, environment-derived values available in the page context, or deceptive log content into agent logs, creating an information disclosure and log-injection channel with no warning or sanitization.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# Convert to PDF
print("Converting to PDF...")
result = subprocess.run(
[
"soffice",
"--headless",
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# Convert PDF to images
print(f"Converting to images at {dpi} DPI...")
result = subprocess.run(
["pdftoppm", "-jpeg", "-r", str(dpi), str(pdf_path), str(temp_dir / "slide")],
capture_output=True,
text=True,
No suspicious patterns detected.