Back to skill

Security audit

QuickClass作业转换器

Security checks for vulnerabilities and agentic risk

Overview

The skill is broadly purpose-aligned, but one image-document helper can read and embed local image files outside the intended folder if given a crafted mapping file.

Install only if you trust the source materials and mapping JSON files you process. Review generated DOCX image documents before sharing them, and avoid running the image-document helper on mapping files from untrusted parties until path confinement is added.

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/generate_image_doc.py:63
Finding

Path Traversal Enables Unauthorized Local Image Disclosure

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_image_doc.py:63-67 and scripts/generate_image_doc.py:190-196
Vulnerability Type: Path traversal and arbitrary local file read
Risk Level: Medium

Vulnerable Code

python
page_path = os.path.join(pages_dir, source_page)
if not os.path.exists(page_path):
    raise FileNotFoundError(f"整页渲染图不存在: {page_path}")

img = Image.open(page_path)

The independent-image processing path contains the same issue:

python
elif image_file:
    # 使用独立图片文件
    image_path = os.path.join(images_dir, image_file)

if not image_path or not os.path.exists(image_path):
    skip_para = doc.add_paragraph()

The selected file is subsequently opened and inserted into the generated document:

python
with PILImage.open(image_path) as img:
    img_width, img_height = img.size

max_width_cm = 14
aspect = img_height / img_width
display_width = min(max_width_cm, img_width * 2.54 / 96)

img_para = doc.add_paragraph()
img_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
img_run = img_para.add_run()
img_run.add_picture(image_path, width=Cm(display_width))

Technical Analysis

The source_page and image_file values originate from the user-supplied mapping JSON. They are joined directly with pages_dir or images_dir without rejecting absolute paths, resolving traversal components, or verifying that the resulting path remains inside the intended directory.

For example, a mapping entry can use:

json
{
  "image_file": "../../private/sensitive-image.png",
  "question_number": 1,
  "page": 1,
  "context": "Question illustration"
}

Because os.path.join() does not enforce directory confinement, .. components can escape the configured image directory. An absolute image_file or source_page can also cause the base directory to be discarded entirely. If the target is a supported image readable by the process, the script opens it and embeds it in the generated DOCX.

The issue affects both support ...[truncated 1300 chars]

Remediation
View remediation

Remediation Suggestions

Resolve and validate every mapping-provided path before opening it:

python
from pathlib import Path

def confined_file(base_dir: str, untrusted_name: str) -> Path:
    base = Path(base_dir).resolve()

    candidate_input = Path(untrusted_name)
    if candidate_input.is_absolute():
        raise ValueError("Absolute image paths are not permitted")

    candidate = (base / candidate_input).resolve()

    try:
        candidate.relative_to(base)
    except ValueError:
        raise ValueError("Image path escapes the configured directory")

    if not candidate.is_file():
        raise FileNotFoundError(f"Image file does not exist: {candidate}")

    return candidate

Apply this validation to both paths:

python
page_path = confined_file(pages_dir, source_page)
image_path = confined_file(images_dir, image_file)

Additional hardening measures should include:

  1. Permit only expected filename forms, such as image_12.png and page_3.png, where practical.
  2. Allowlist supported image extensions and verify the actual decoded image format.
  3. Reject null bytes, absolute paths, traversal components, and symbolic links that resolve outside the base directory.
  4. Validate the mapping JSON against a strict schema before processing it.
  5. Run document generation with minimal filesystem permissions.
  6. Treat mapping files from untrusted sources as hostile input and avoid sharing generated documents until their embedded content has been reviewed.
Vulnerability Patterns
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description says the skill converts learning materials (Word, PDF, images) into QuickClass quiz JSON, implying document/media ingestion and question extraction from those materials. However, this code accepts only a JSON file containing pre-extracted questions and transforms that intermediate structure into QuickClass format. The supported question types do match the description, and the QuickClass JSON conversion purpose is aligned at a lower level, but the important front-end capability of processing raw documents/images is absent. Therefore the description overstates what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

There is a clear description-behavior mismatch. The declared purpose is a content conversion skill that should transform learning materials into QuickClass quiz JSON with supported question types. The supplied code does not build any quiz JSON schema, extract question stems/options/answers, or handle QuickClass-specific output at all. Instead, it is a utility focused on extracting embedded images or rendering PDF pages, then associating those images with question numbers in a separate mapping JSON. While such image extraction could be a supporting subcomponent in a larger exam-to-quiz pipeline, this code chunk by itself has a materially different primary function from the declared skill description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says the skill converts source materials such as Word/PDF/images into QuickClass quiz JSON with specific question types. The supplied code does not parse learning materials into quiz content or emit QuickClass JSON at all. Its primary function is to create a companion Word document containing labeled question images, using an existing mapping JSON and optional crop coordinates from page renderings. While the docstrings mention QuickClass as context, the behavior is clearly auxiliary image-document generation, not quiz conversion. This is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill instructs the agent to read source documents, write intermediate files under .temp/, and generate output JSON/DOCX files, but it declares no explicit tool scope such as permissions or allowed-tools. That creates an overbroad execution surface where the runtime may permit more file access than the task actually needs, increasing the chance of unintended file reads/writes or misuse if the skill is invoked with adversarial inputs or in a permissive environment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The visible skill content is written entirely in Chinese and does not state that users may interact in another language or choose their preferred locale. Under the language/locale policy rule, this can be a natural-language policy violation unless the skill explicitly offers opt-in or clearly documents a justified region-specific restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file presents all user-facing instructions, examples, and schema guidance exclusively in Chinese. Under the policy, forcing a specific language without user opt-in or a clearly documented regional justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code file contains user-facing natural language in the module docstring and command usage text that assumes Chinese as the required language. Under the policy, forcing a specific language without an explicit user choice or documented justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The argparse description and all help strings are presented only in Chinese, creating a fixed-language interface for users of the skill. There is no opt-in, alternative locale, or justification indicating that the skill is intentionally restricted to a Chinese-language environment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language documentation and command help that exclusively uses Chinese, including the module docstring and later CLI/help output. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.