Back to skill

Security audit

sn-ppt-entry

Security checks for vulnerabilities and agentic risk

Overview

This PPT generation skill is mostly on-purpose, but it includes an unsafe command template and loosely scoped helper behavior that should be reviewed before installation.

Install only after reviewing the command-template issue. The skill will read uploaded documents and images, write PPT artifacts, call configured model services, and may start a local progress WebUI. Avoid using it with untrusted prompts or documents until the digest command is moved into a real script with arguments passed as data, PPT_STANDARD_DIR is constrained to a trusted install path, and parser dependencies are pinned.

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

Error
Location
SKILL.md:144
Finding

Command Injection Through Unsafe User-Query Interpolation in a Shell-Embedded Python Program

Content
View full analysis
/raw_documents.json').read_text()) # Build the digest-safe view: strip tables[] and image paths, keep text + indices docs_view = [] for d in raw.get('documents', []): docs_view.append({ 'doc_index': d['doc_index'], 'type': d['type'], 'text': d.get('text',''), 'tables_count': len(d.get('tables') or []), 'images_count': len(d.get('inherited_images') or []), }) user_prompt = json.dumps({ 'user_query': '', 'documents': docs_view, }, ensure_ascii=False) sys_prompt = open('$SKILL_DIR/prompts/document_digest.md').read() out = llm(sys_prompt, user_prompt) # Parse JSON; if it fails, degrade digest to null (not abort entry) try: digest = json.loads(out) except Exception: digest = None pathlib.Path('/digest_tmp.json').write_text(json.dumps(digest, ensure_ascii=False)) " ``` ### Technical Analysis The documented command builds Python source code by directly substituting the original user query into a `python3 -c` program. The entire Python program is enclosed in shell double quotes. Shell expansion occurs before Python receives the source code. Consequently, shell constructs embedded in the user query—particularly command substitutions such as `$(command)` or backtick substitutions—can be executed by the shell even though the substitution point visually appears inside a single-quoted Python string. Python single quotes have no protective meaning to the outer shell. The query can also contain quotes, newlines, or Python syntax that terminates the intended string literal and modifies the generated Python program. ...[truncated 2246 chars]
Remediation
View remediation
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Content

No source excerpt is available for this finding.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

There is a clear description-behavior mismatch. The declared purpose describes an orchestration/entry skill for presentation generation, including user interaction, mode selection, document parsing, task/info pack creation, and dispatching to other skills. The supplied code instead performs a narrow backend function: captioning images already referenced in an existing deck directory using a vision-language model, then caching results into JSON. None of the key declared entry-point behaviors are present, and the actual capability—image caption generation and JSON mutation—is undeclared and materially different from the stated primary purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description is for a high-level PPT generation entry skill/orchestrator. The supplied code chunk is only a parser for uploaded documents. While document parsing is one supporting detail mentioned in the description, the code does not implement the core declared behavior: prompting for modes/options, deciding between fast/standard/creative flows, preparing deck artifacts, or dispatching to downstream PPT-generation skills. Its actual behavior is materially narrower and different in primary purpose, so this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for a high-level PPT generation entry skill, including user prompting, document parsing, artifact creation, and routing to other skills. The supplied code does none of that. It is a narrow utility module for reading and writing timing.json, with commands to initialize timing data and accumulate stage/per-page timing values. This is a materially different primary purpose, not merely a supporting implementation detail of the declared entry skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill is instructed to infer the user's language without asking and to default to Simplified Chinese when uncertain. Forced inference can mis-handle user intent, generate content in the wrong language, and silently alter outputs, which is especially risky in a document-generation workflow where correctness and user expectations matter.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill performs environment access and file reads/writes but declares no explicit tool scope or permissions boundary. In an agent environment, missing scope declarations can allow broader-than-intended capability exposure, making accidental or abusive filesystem/env access harder to constrain or audit.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Broad trigger phrases around making presentations can overlap with ordinary user conversation, increasing the chance the skill auto-invokes unexpectedly. Over-broad activation is risky in agent systems because it can start file operations, environment checks, or dispatch chains without clear user intent.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
82% confidence
Finding

The instruction to make autonomous decisions about language and other inferred parameters without user confirmation expands agent autonomy in a user-facing generation workflow. This can lead to unauthorized or incorrect actions, especially when combined with downstream file creation and skill dispatch.

Content

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

md
- `audience`
   - `scene` (where the deck will be used)
   - `page_count`
   - `language` — detect from the user's query: `zh-Hans` (Simplified Chinese), `zh-Hant` (Traditional Chinese), or `en` (English). Do NOT ask the user; just infer and record it. If unsure, use `zh-Hans`.
2. If the user asks only to open/preview/edit an existing generated deck in the WebUI, dispatch to `/skill sn-ppt-workbench deck_dir=<abs-or-user-provided-path>` and stop. Do not ask mode questions.
3. If `task_pack.json` + `info_pack.json` already exist in a deck_dir the user refers to and the user asks to continue generation, read them and jump to step 10 (see "Resume" below).
4. **Always ask the user which mode to use first.** Call `ask_user`:

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
**Question — Normal images (decorative / conceptual):**
   "Should I include images, and how should they be sourced?"
   - "AI generation — create images from scratch"
   - "Web search — pull real photos from the web (requires Serper API key)"
   - "No images — use text, charts, and CSS visuals only"

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill contains contradictory decision rules: one section forbids proceeding with assumed/default values after asking, while another requires inferring defaults and continuing in fast/creative modes. Ambiguous control logic in agent skills is dangerous because it can cause the agent to bypass user confirmation, perform unintended actions, or behave inconsistently under adversarial prompting.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The handoff section omits fast mode even though earlier logic supports it, creating an incomplete or conflicting dispatch contract. In an agent pipeline, such ambiguity can cause incorrect downstream invocation, dropped safety checks, or fallback to unintended behaviors when the mode is fast.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The heading "PPT 系 skill 共用约定" and the entire document are written only in Chinese, establishing a language-specific convention for shared skills. There is no indication that users may choose another language or that the Chinese-only constraint is required for a region-specific or compliance reason.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script dynamically imports and executes Python code from a path controlled by the PPT_STANDARD_DIR environment variable. If an attacker can influence that environment variable or place a malicious model_client.py in the referenced directory, they can achieve arbitrary code execution when this helper runs; in this PPT-generation pipeline context, that exceeds the intended image-captioning behavior and is a genuine supply-chain/local code injection risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The natural-language system and user prompts explicitly require the model to produce captions in Chinese. This imposes a specific language on all users with no opt-in, fallback, or documented region-specific rationale, which matches the locale-policy violation criteria.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is specified with a lower-bound only (pypdf>=4.0), which makes builds non-reproducible and allows future installations to pull in unexpected versions, including ones later found vulnerable or behaviorally incompatible. In this skill, pypdf parses user-supplied PDF files, so dependency drift increases security risk because parser libraries are exposed to adversarial input.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
pypdf>=4.0
python-docx>=1.1

Unverifiable Dependency: pypdf has 16 known advisory(ies) (CVE-2026-84310 (pypdf: Possible long runtimes/large memory usage when retrieving outlines); CVE-2026-48156 (pypdf: Possible long runtimes for zero-only width values in cross-reference stre); CVE-2026-24688 (pypdf has possible Infinite Loop when processing outlines/bookmarks) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

pypdf has multiple known advisories, and because the manifest does not pin a version, it is impossible to determine whether deployed environments are using a fixed or affected release. This is more concerning here because the skill explicitly ingests uploaded PDFs, so parser flaws such as denial-of-service via excessive runtime or memory use are directly reachable by attackers through crafted files.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is unpinned (python-docx>=1.1), so installs may resolve to different versions over time, weakening reproducibility and making it hard to verify whether known fixes are present. Because this skill parses uploaded DOCX files, using an uncontrolled parser version raises risk from malformed or malicious documents.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
pypdf>=4.0
python-docx>=1.1

Unverifiable Dependency: python-docx has 2 known advisory(ies) (CVE-2016-5851 (Improper Restriction of XML External Entity Reference in python-docx); CVE-2016-5851 (python-docx before 0.8.6 allows context-dependent attackers to conduct XML Exter)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

python-docx has historical security advisories, including XXE-related issues, and the lack of version pinning means the installed release cannot be verified as patched. Since this skill parses user-uploaded DOCX files, an affected parser could expose the system to malicious document processing behavior, potentially including external entity abuse or denial of service depending on runtime configuration.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.