Back to skill

Security audit

Wps Skill

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed WPS automation skill, but it needs review because it can create files outside its intended folder and type into the active window without strong safeguards.

Review before installing. Use it only in a test or trusted document folder, avoid broad batch-conversion targets, do not convert untrusted Markdown, and keep WPS 365 credentials blank unless needed. If credentials are used, use a least-privilege WPS app secret and avoid shared machines. Install dependencies in an isolated environment with pinned versions where possible.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:60
Finding

Arbitrary File Creation Through Path Traversal

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:60-73, with attacker-controlled input passed at scripts/main.py:1519-1524
Vulnerability Type: Path traversal and unrestricted file creation
Risk Level: High

Vulnerable Code

python
filepath = os.path.join(self.default_save_path, filename)

# Select the WPS component based on document type
app_map = {
    "writer": "wps",
    "spreadsheet": "et",
    "presentation": "wpp"
}

app = app_map.get(doc_type, "wps")

# Create an empty file
Path(filepath).touch()

The filename value is supplied directly from command-line parameters:

python
if action == 'create':
    result = wps.create_document(
        doc_type=params.get('type', 'writer'),
        filename=params.get('filename', 'New Document.docx'),
        content=params.get('content', '')
    )

Technical Analysis

The destination path is constructed by passing an unvalidated, attacker-influenced filename to os.path.join(). The code does not reject absolute paths, parent-directory components such as ../, or symbolic-link traversal. It also does not resolve the resulting path and verify that it remains beneath default_save_path.

An absolute second argument causes os.path.join() to discard the intended base directory. A relative path containing enough parent-directory components can similarly escape the configured document directory. Path.touch() then creates the resolved file using the privileges of the process.

The operation does not normally truncate an existing file, but it can create new empty files in arbitrary writable locations and update timestamps on existing files.

Attack Path

  1. An attacker supplies, or causes the Agent to generate, a document-creation request with a crafted filename such as ../../../../tmp/attacker-controlled.
  2. The Agent invokes scripts/main.py create and passes that value through the filename paramete ...[truncated 967 chars]
Remediation
View remediation

Remediation Suggestions

  • Reject absolute filenames and any path containing parent-directory traversal components.
  • Resolve both the configured base directory and candidate destination before writing.
  • Verify that the resolved destination is a child of the resolved base directory.
  • Define an explicit filename policy, including permitted characters, length, and document extensions.
  • Consider rejecting path separators entirely if the interface is intended to accept only filenames.
  • Avoid following symbolic links when creating files where supported.
  • Open new files with exclusive-creation semantics if overwriting or touching existing files is not intended.

Example hardening logic:

python
base = Path(self.default_save_path).expanduser().resolve()
supplied = Path(filename)

if supplied.is_absolute() or ".." in supplied.parts:
    raise ValueError("Invalid filename")

destination = (base / supplied).resolve()

try:
    destination.relative_to(base)
except ValueError:
    raise ValueError("Destination escapes the configured save directory")

destination.parent.mkdir(parents=True, exist_ok=True)
destination.touch(exist_ok=False)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:210
Finding

Unescaped Markdown Content Is Emitted as Active HTML and RTF Syntax

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:210-295
Vulnerability Type: Output injection in generated HTML and RTF documents
Risk Level: Medium

Vulnerable Code

python
# Process Markdown content
lines = md_content.split('\n')
for line in lines:
    # Headings
    if line.startswith('# '):
        rtf += r'\b\fs32 ' + line[2:] + r'\b0\fs22\par '
    elif line.startswith('## '):
        rtf += r'\b\fs28 ' + line[3:] + r'\b0\fs22\par '
    elif line.startswith('### '):
        rtf += r'\b\fs24 ' + line[4:] + r'\b0\fs22\par '
    # Lists
    elif line.startswith('- ') or line.startswith('* '):
        rtf += r'\bullet  ' + line[2:] + r'\par '
    # Bold text
    elif '**' in line:
        parts = re.split(r'\*\*(.*?)\*\*', line)
        for i, part in enumerate(parts):
            if i % 2 == 1:
                rtf += r'\b ' + part + r'\b0 '
            else:
                rtf += part + ' '
        rtf += r'\par '
    # Normal paragraphs
    elif line.strip():
        rtf += line + r'\par '
python
for line in lines:
    # Headings
    if line.startswith('# '):
        if in_list:
            html += '</ul>\n'
            in_list = False
        html += f'<h1>{line[2:]}</h1>\n'
    elif line.startswith('## '):
        if in_list:
            html += '</ul>\n'
            in_list = False
        html += f'<h2>{line[3:]}</h2>\n'
    elif line.startswith('### '):
        if in_list:
            html += '</ul>\n'
            in_list = False
        html += f'<h3>{line[4:]}</h3>\n'
    elif line.startswith('- ') or line.startswith('* '):
        if not in_list:
            html += '<ul>\n'
            in_list = True
        content = line[2:]
        content = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', content)
        html += f'<li>{content}</li>\n'
    elif line.strip():
        if in_list:
            ht
...[truncated 2383 chars]
Remediation
View remediation

Remediation Suggestions

  • Escape all text before placing it into HTML by using html.escape() with quotation escaping enabled.
  • Escape RTF metacharacters, particularly backslashes, opening braces, and closing braces.
  • Encode Unicode characters according to the RTF specification rather than inserting arbitrary raw text.
  • Prefer a mature, maintained Markdown conversion library over a custom parser.
  • Disable or sanitize raw HTML in Markdown unless active HTML is an explicitly documented feature.
  • Do not automatically open files generated from untrusted input without explicit user confirmation.
  • Apply output-size limits to reduce document-parser denial-of-service risks.
  • Add tests containing HTML tags, ampersands, braces, backslashes, Unicode, external-resource elements, and malformed formatting sequences.

Minimal HTML escaping example:

python
import html

safe_content = html.escape(content, quote=True)
html_output += f"<p>{safe_content}</p>\n"

Minimal RTF text escaping should include logic equivalent to:

python
def escape_rtf(value):
    return value.replace("\\", r"\\").replace("{", r"\{").replace("}", r"\}")

T08 · Insecure Dependencies

Warning
Location
SKILL.md:47
Finding

Third-Party Python Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:47
Vulnerability Type: Unpinned and unverifiable dependency installation
Risk Level: Medium

Vulnerable Code

bash
pip install requests pyautogui pyperclip Pillow

Technical Analysis

The installation instructions request dependency names without exact versions, cryptographic hashes, a lockfile, or an explicitly trusted package index. As a result, installation resolves whatever package versions the configured Python package index considers current at installation time.

This makes the installed code non-reproducible and allows reviewed behavior to change without any modification to the skill package. If an upstream account, package distribution, package index, or local package-index configuration is compromised, malicious package code could execute during installation or later import.

The project also has inconsistent dependency declarations: SKILL.md includes requests, while skill.json declares only pyautogui, pyperclip, and Pillow. This can encourage ad hoc dependency installation outside a controlled lockfile.

Attack Path

  1. A user follows the documented installation command.
  2. pip queries the user's configured package index or indexes.
  3. Because no versions or hashes are specified, pip accepts mutable package releases satisfying its default resolution rules.
  4. A compromised upstream release, package-index response, or dependency selected by the resolver is downloaded.
  5. Package installation or subsequent import executes attacker-controlled Python code with the privileges of the installing or Agent account.

This audit did not identify a currently malicious named dependency. The vulnerability is the absence of controls needed to ensure that installed artifacts are the exact reviewed artifacts.

Impact Assessment

A malicious dependency can execute arbitrary code with the privileges of the environment running inst ...[truncated 410 chars]

Remediation
View remediation

Remediation Suggestions

  • Create a reviewed requirements or lock file containing exact dependency versions.
  • Record SHA-256 hashes for every direct and transitive distribution.
  • Install with hash enforcement, for example:
bash
python -m pip install --require-hashes -r requirements.txt
  • Keep SKILL.md, skill.json, and the lockfile synchronized so that all runtime dependencies are declared consistently.
  • Use an isolated virtual environment and avoid administrative installation.
  • Document the approved package index and disable unintended supplemental indexes.
  • Run automated vulnerability and provenance checks when updating dependencies.
  • Review package release artifacts before changing pinned versions.
  • Add the missing requests dependency to the authoritative dependency manifest if the WPS 365 implementation is retained.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (16)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Sending keystrokes to the current active window is dangerous because focus may have shifted to a different application, causing unintended commands, data disclosure, or modification of unrelated content. In an agent skill, silent GUI automation can act on the wrong target and is especially risky because the content is user-controlled and no verification of window identity occurs.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger list is very broad and includes common terms like 'wps', '文档', '表格', 'excel', and 'word', which can cause the skill to activate on many normal user requests unrelated to an explicit desire to run this automation. Because the skill exposes an exec-capable tool and is intended to create, edit, convert, and batch-process files, accidental invocation could lead to unintended file modification or command execution in a sensitive context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents a bulk operation that affects an entire directory of documents, but the surrounding description does not warn users about the scope, destination, or potential overwrite/large-scale processing impact. Under the markdown criteria, behaviors that could affect user data should include a clear warning.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level module docstring describes a WPS Office automation skill focused on local document operations such as creating, opening, saving, converting, and batch processing files. However, the file also exposes many additional actions for remote WPS 365 resources, including listing/submitting forms, sharing online docs, and managing sheets, flowcharts, and mind maps, which materially exceeds that described scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill creates local files at user-influenced paths without confirmation, and Path.touch() can overwrite timestamps or create arbitrary files under the configured save directory. In an agent context, silent filesystem writes are risky because they can alter user data or plant misleading documents without explicit user awareness.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/main.py (reported line 84)May include surrounding context.

python
else:
                cmd = [app, filepath]
            
            subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            
            # 如果有内容,等待 WPS 打开后输入
            if content:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/main.py (reported line 121)May include surrounding context.

python
else:
                cmd = [app, filepath]
            
            subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            
            # 如果有内容,等待 WPS 打开后输入
            if content:

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The docstring and returned success message indicate that a document format conversion has completed. In reality, except for the Markdown special case, the function does not invoke WPS, transform file contents, or create the output file; it merely computes an output path and reports success, which directly contradicts the documented behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The conversion helpers write output files to disk automatically, potentially replacing expected artifacts or creating files in sensitive locations derived from the input path. In a skill setting, undisclosed writes increase the risk of unwanted persistence, data sprawl, and accidental overwriting of user content.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/main.py (reported line 182)May include surrounding context.

python
f.write(rtf_content)
                
                # 用 WPS 打开 RTF 文件
                subprocess.Popen(['open', '-a', 'WPS Office', rtf_file], 
                               stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                
                return {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code performs authenticated outbound API calls using configured credentials and user-supplied data without any visible disclosure or consent flow. In an agent environment, silent network transmission can expose sensitive business data to external services and may surprise users who expected only local document automation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest advertises document creation, editing, format conversion, and batch processing, but does not warn that these operations may overwrite, transform, or bulk-modify user files. In the context of an automation skill with exec access, lack of disclosure and safety prompts increases the chance of destructive or surprising actions being performed on user data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill documentation forces a specific language for instructions and usage examples, which can violate language/locale policy when no user opt-in or justification is provided. There is no indication that this skill is intentionally limited to a Chinese-speaking or region-specific audience.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file contains user-facing instructions and operational guidance exclusively in Chinese, starting with the section headings and continuing throughout the document. Under the policy rule, forcing a specific language without user opt-in can be a natural-language policy violation when no alternative language option or justification is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The module-level description and user-facing messages are written in Chinese without indicating that another language can be used. This can violate a language or locale policy when the skill effectively forces one locale without user opt-in or documented justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest description is presented only in Chinese, which may impose a language expectation without offering user choice or documenting that the skill is intended for a Chinese-language audience. This can conflict with language or locale policy when no opt-in or justification is provided.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.