Back to skill

Security audit

Pptx Anthropic

Security checks for vulnerabilities and agentic risk

Overview

This presentation skill is mostly coherent, but it uses risky native LibreOffice shimming and broad file-modifying helpers that need review before installation.

Install only in an isolated, unprivileged environment and use copies of presentations. Be especially cautious with untrusted PPTX files, because rendering may invoke LibreOffice with a native LD_PRELOAD shim, and avoid relying on the bundled DOCX/XLSX helpers unless you intentionally want broader Office-document behavior.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (4)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/office/soffice.py:24
Finding
Predictable Shared Library Path Enables LD_PRELOAD Hijacking<![CDATA[ ## Vulnerability Details **File Location**: `scripts/office/soffice.py:24-31, 41-64` **Vulnerability Type**: Unsafe temporary file reuse and dynamic-loader hijacking **Risk Level**: High ### Vulnerable Code ```python def get_soffice_env() -> dict: env = os.environ.copy() env["SAL_USE_VCLPLUGIN"] = "svp" if _needs_shim(): shim = _ensure_shim() env["LD_PRELOAD"] = str(shim) return env _SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so" def _ensure_shim() -> Path: if _SHIM_SO.exists(): return _SHIM_SO src = Path(tempfile.gettempdir()) / "lo_socket_shim.c" src.write_text(_SHIM_SOURCE) subprocess.run( ["gcc", "-shared", "-fPIC", "-o", str(_SHIM_SO), str(src), "-ldl"], check=True, capture_output=True, ) src.unlink() return _SHIM_SO ``` ### Technical Analysis The helper stores its native shim at the predictable shared path `/tmp/lo_socket_shim.so`. If that path already exists, `_ensure_shim()` accepts it without checking its owner, permissions, file type, content, or cryptographic digest. `get_soffice_env()` subsequently places the accepted path in `LD_PRELOAD`. The dynamic loader therefore loads the shared object into the LibreOffice process before normal libraries. A malicious shared object can use a constructor function to execute arbitrary native code immediately when LibreOffice starts. The same predictable path also creates a time-of-check/time-of-use risk. Even if the legitimate script initially determines that the file does not exist, another local process may attempt to replace or redirect the output while compilation is occurring. The predictable C source path is similarly unsafe, although compromise of the resulting shared object is the primary risk. ### Attack Path 1. The attacker has access as another local user or through another process sharing the same temporary directory. 2. Before the Skill invokes LibreOffice, the attacker cre ...[truncated 1016 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create a private temporary directory with permissions limited to the current user, such as mode `0700`. - Generate both the C source and compiled library inside that private directory using unpredictable names. - Create files atomically and reject symbolic links. - Do not reuse an existing shared object merely because it exists. - If caching is necessary, verify the file owner, mode, regular-file status, expected hash, and containing-directory permissions before use. - Compile to a temporary output and atomically rename it only after successful compilation. - Remove the library after the LibreOffice process exits. - Prefer redesigning the integration so that `LD_PRELOAD` is unnecessary. - Invoke the compiler by a trusted absolute path or execute it in a tightly controlled environment. A safer structure is: ```python with tempfile.TemporaryDirectory(prefix="lo-shim-") as temp_dir: private_dir = Path(temp_dir) private_dir.chmod(0o700) src = private_dir / "shim.c" shim = private_dir / "shim.so" src.write_text(_SHIM_SOURCE, encoding="utf-8") subprocess.run( ["/usr/bin/gcc", "-shared", "-fPIC", "-o", str(shim), str(src), "-ldl"], check=True, capture_output=True, ) env["LD_PRELOAD"] = str(shim) # Start and wait for LibreOffice before leaving this context. ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/add_slide.py:89
Finding
Unvalidated Slide Source Allows Path Traversal and Local File Copying<![CDATA[ ## Vulnerability Details **File Location**: `scripts/add_slide.py:89-117, 183-195` **Vulnerability Type**: Path traversal and unintended local-file inclusion **Risk Level**: Medium ### Vulnerable Code ```python def duplicate_slide(unpacked_dir: Path, source: str) -> None: slides_dir = unpacked_dir / "ppt" / "slides" rels_dir = slides_dir / "_rels" source_slide = slides_dir / source if not source_slide.exists(): print(f"Error: {source_slide} not found", file=sys.stderr) sys.exit(1) next_num = get_next_slide_number(slides_dir) dest = f"slide{next_num}.xml" dest_slide = slides_dir / dest source_rels = rels_dir / f"{source}.rels" dest_rels = rels_dir / f"{dest}.rels" shutil.copy2(source_slide, dest_slide) if source_rels.exists(): shutil.copy2(source_rels, dest_rels) ``` ```python unpacked_dir = Path(sys.argv[1]) source = sys.argv[2] if not unpacked_dir.exists(): print(f"Error: {unpacked_dir} not found", file=sys.stderr) sys.exit(1) source_type, layout_file = parse_source(source) if source_type == "layout" and layout_file is not None: create_slide_from_layout(unpacked_dir, layout_file) else: duplicate_slide(unpacked_dir, source) ``` ### Technical Analysis The `source` command-line argument is appended directly to the slide directory without restricting it to an expected filename such as `slide2.xml`. `Path` preserves relative traversal components, so a value containing `../` can resolve outside `unpacked_dir/ppt/slides`. The script only checks whether the resulting path exists. It does not resolve the path and verify that it remains under the intended slide directory. `shutil.copy2()` consequently copies the selected external file into the unpacked presentation as a newly named slide. Normal packing parses files ending in `.xml`, which limits straightforward disclosure through the standard workflow to content that can pass XML processing. Nevertheless, readab ...[truncated 1340 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require slide sources to match a strict allowlist pattern: ```python if not re.fullmatch(r"slide[1-9][0-9]*\.xml", source): raise ValueError("Source must be a slide filename such as slide2.xml") ``` - Reject absolute paths, path separators, null bytes, `.` components, and `..` components. - Resolve the source and base directory and enforce containment: ```python slides_root = (unpacked_dir / "ppt" / "slides").resolve() source_path = (slides_root / source).resolve() if source_path.parent != slides_root: raise ValueError("Slide source escapes the slides directory") if not source_path.is_file(): raise ValueError("Slide source is not a regular file") ``` - Apply equivalent basename and containment validation to `layout_file`. - Reject symbolic links or verify the resolved target immediately before opening it. - Parse the selected slide as XML and verify that its root element is an OOXML presentation slide before copying it. - Avoid `sys.exit()` inside reusable functions; raise explicit exceptions so callers cannot accidentally ignore partial operations. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/office/unpack.py:45
Finding
Unbounded Office Archive Extraction Enables Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/office/unpack.py:45-54` **Additional Locations**: `scripts/office/validate.py:73-74`, `scripts/office/validators/base.py:801-802`, `scripts/office/validators/redlining.py:61-64` **Vulnerability Type**: Unrestricted archive extraction and decompression bomb exposure **Risk Level**: Medium ### Vulnerable Code ```python if suffix not in {".docx", ".pptx", ".xlsx"}: return None, f"Error: {input_file} must be a .docx, .pptx, or .xlsx file" try: output_path.mkdir(parents=True, exist_ok=True) with zipfile.ZipFile(input_path, "r") as zf: zf.extractall(output_path) ``` The same extraction pattern is used during validation: ```python with zipfile.ZipFile(self.original_file, "r") as zip_ref: zip_ref.extractall(temp_path) ``` ### Technical Analysis Office documents are ZIP archives. The code validates only the filename suffix and then extracts every member without checking: - Number of archive entries - Total uncompressed size - Per-entry uncompressed size - Compression ratio - Available disk capacity - Duplicate member names - Unexpected file types - Processing-time limits A small malicious PPTX, DOCX, or XLSX can therefore contain highly compressible data that expands to a very large size. Following extraction, `unpack.py` recursively locates XML and relationship files and processes them, increasing CPU and memory consumption further. Temporary extraction in validators reduces persistence of files after normal completion, but it does not prevent disk exhaustion while extraction is in progress. ### Attack Path 1. The attacker creates a ZIP archive with a permitted Office extension. 2. The archive contains one or more entries with a very high compression ratio or an excessive number of files. 3. The archive is submitted to the normal unpacking, packing-validation, or redlining-validation workflow. 4. `extractall()` expands all entries without checking limits. 5. Disk space, ...[truncated 598 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Inspect all `ZipInfo` records before extracting any entry. - Enforce explicit limits for: - Maximum number of members - Maximum uncompressed size per member - Maximum aggregate uncompressed size - Maximum compression ratio - Maximum filename length and path depth - Reject encrypted entries, duplicate normalized paths, unsupported compression methods, and non-regular entry types unless explicitly required. - Extract entries individually rather than using `extractall()`. - Resolve each destination and verify that it remains under the extraction root. - Stop extraction immediately when a limit is exceeded and remove partial output. - Apply process-level disk, memory, CPU, and execution-time limits. - Use one shared hardened extraction function across `unpack.py`, `validate.py`, `base.py`, and `redlining.py`. Example preflight logic: ```python MAX_FILES = 10_000 MAX_ENTRY_SIZE = 100 * 1024 * 1024 MAX_TOTAL_SIZE = 500 * 1024 * 1024 MAX_RATIO = 200 infos = zf.infolist() if len(infos) > MAX_FILES: raise ValueError("Archive contains too many entries") total = 0 for info in infos: if info.file_size > MAX_ENTRY_SIZE: raise ValueError("Archive member is too large") total += info.file_size if total > MAX_TOTAL_SIZE: raise ValueError("Archive expands beyond the permitted size") if info.compress_size == 0 and info.file_size > 0: raise ValueError("Suspicious compression metadata") if info.compress_size and info.file_size / info.compress_size > MAX_RATIO: raise ValueError("Suspicious compression ratio") ``` ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:226
Finding
Unpinned Global Dependency Installation Creates Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:226-230` **Additional Location**: `pptxgenjs.md:238` **Vulnerability Type**: Unpinned third-party dependencies and global package installation **Risk Level**: Low ### Vulnerable Code ```markdown ## Dependencies - `pip install "markitdown[pptx]"` - text extraction - `pip install Pillow` - thumbnail grids - `npm install -g pptxgenjs` - creating from scratch - LibreOffice (`soffice`) - PDF conversion - Poppler (`pdftoppm`) - PDF to images ``` An additional instruction states: ```markdown Install: `npm install -g react-icons react react-dom sharp` ``` ### Technical Analysis The installation commands do not specify reviewed versions, integrity hashes, or lockfiles. They therefore resolve to whichever package versions the registries serve at installation time. The npm commands also use global installation. Depending on the environment, this can modify shared tool locations and expose other workflows to the newly installed package versions. npm package lifecycle scripts may execute during installation. No evidence was found that the named packages are intentionally malicious or typosquatted. The vulnerability is the non-reproducible and unnecessarily broad installation method, which increases exposure to a future compromised release, registry compromise, dependency takeover, or incompatible update. ### Attack Path 1. A direct or transitive dependency release is compromised, its maintainer account is taken over, or the registry serves a malicious version. 2. The Agent follows the documented unpinned installation command. 3. The package manager selects the compromised current version. 4. Package installation code or lifecycle scripts execute with the installing user's privileges. 5. The compromised package gains access to resources available to that user and may affect later invocations from the global installation location. ### Impact Assessment Impact depends on the privileges of the account ...[truncated 474 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin every direct dependency to a reviewed exact version. - Maintain lockfiles for Python and Node.js dependency trees. - For Python, use hash-verified installation, for example a locked requirements file with `--require-hashes`. - For npm, use a project-local `package.json` and committed lockfile, then install with `npm ci`. - Avoid `npm install -g`; use project-local binaries through controlled scripts. - Run dependency installation in an isolated, unprivileged virtual environment or container. - Review transitive dependencies and monitor them for known vulnerabilities. - Restrict or disable package lifecycle scripts where compatible with required packages. - Obtain packages only from configured trusted registries and retain provenance or integrity metadata. - Separate dependency installation from processing untrusted presentation content. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (44)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the skill package really includes generic LibreOffice subprocess execution plus LD_PRELOAD shims while presenting itself as a simple PPTX utility, that hidden execution complexity materially increases risk. It can expose arbitrary document-conversion surfaces and environment manipulation not obvious from the trigger text, making misuse and exploitation through crafted documents or prompts more likely.

Vague Triggers

High
Confidence
97% confidence
Finding
The trigger language is extremely broad: any mention of decks, slides, presentations, or .pptx files invokes the skill. In an agent system, overly broad routing can cause powerful shell/file-modifying workflows to activate in contexts where they are unnecessary, increasing exposure to prompt injection in document content and accidental destructive operations.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The helper operates on DOCX internals (`word/document.xml`) even though the skill is declared as PPTX-only. In an agent setting, this scope mismatch is dangerous because a PPTX-triggered workflow could unexpectedly read or modify Word documents, violating user expectations and enabling unintended cross-format file tampering.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
def get_soffice_env() -> dict:
    env = os.environ.copy()
    env["SAL_USE_VCLPLUGIN"] = "svp"

    if _needs_shim():
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
Setting LD_PRELOAD to inject a custom shared library into LibreOffice changes process behavior at the dynamic linker level, which is a powerful and dangerous capability. In a .pptx-processing skill, this is far outside expected functionality and creates a covert execution path for arbitrary native code whenever the helper runs.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
Invoking a system compiler to build executable native code is unnecessary for routine presentation processing and introduces a supply-chain and local-environment trust dependency. If gcc, temp files, or resulting artifacts are tampered with, the skill can execute attacker-influenced code under the agent's privileges.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The embedded shim hooks libc socket, listen, accept, and close to bypass AF_UNIX restrictions and even forces process exit in close(). Intercepting core libc behavior is highly invasive, can destabilize execution, and is effectively a sandbox-evasion technique that is inappropriate for a presentation skill.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This file implements Word .docx redlining validation even though the declared skill scope is PPTX-only. That capability mismatch weakens trust boundaries and may cause the agent to process document types outside its intended domain, increasing the chance of unintended file handling, hidden data flows, or policy bypass through mislabeled skill behavior.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises shell execution and file read/write workflows but does not declare any explicit tool scope or allowed-tools constraints. In an agent environment, that increases the blast radius of prompt injection or operator error because the skill can induce use of powerful capabilities without an auditable least-privilege boundary.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation instructs unpacking, manipulating, cleaning, and packing presentation files but does not warn users that these steps modify files and can create new artifacts. Missing warnings reduce informed consent and increase the chance of accidental data loss, corruption, or unintended modification of untrusted documents.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The module docstring explicitly describes DOCX run-merging behavior, which contradicts the skill metadata that says the skill should be used for PPTX files. This inconsistency increases the risk of unsafe routing and maintenance mistakes, because operators and downstream automation may trust the declared PPTX-only boundary while the code is built to alter Word documents.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function writes modified XML back to `word/document.xml` in place with no confirmation, backup, or dry-run mode. In an automated agent context, silent in-place mutation can destroy user data, corrupt documents, or apply unintended edits without visibility, especially when combined with the skill/file-type mismatch.

Static analysis

No suspicious patterns detected.