Back to skill

Security audit

Windows RPA

Security checks for vulnerabilities and agentic risk

Overview

This Windows automation skill is disclosed as powerful desktop control software, but it needs Review because it exposes arbitrary command execution and sensitive desktop access without mandatory safeguards.

Install only if you intentionally want an agent to control a Windows desktop, read clipboard contents, capture the screen, and run local commands. Use it in a low-privilege or sandboxed Windows account, require explicit approval for every shell, run_app, screenshot, clipboard-read, and get_state action, and avoid using it while secrets or sensitive documents are visible or copied.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
rpa.py:248
Finding
Command Injection in Application Launching## Vulnerability Details **File Location**: `rpa.py:248-266` **Vulnerability Type**: OS command injection through unsafe shell invocation **Risk Level**: High ### Vulnerable Code ```python def cmd_launch(args): """启动应用""" app_paths = { "notepad": "notepad.exe", "word": "winword.exe", "excel": "excel.exe", "chrome": "chrome.exe", "firefox": "firefox.exe", "edge": "msedge.exe", "explorer": "explorer.exe", "cmd": "cmd.exe", "powershell": "powershell.exe", "paint": "mspaint.exe", "calc": "calc.exe", } app_path = app_paths.get(args.app.lower(), args.app) try: if args.args: subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True) else: subprocess.Popen(f'start "" "{app_path}"', shell=True) ``` ### Technical Analysis Both `args.app` and `args.args` are incorporated into a command string passed to `subprocess.Popen` with `shell=True`. On Windows, this causes the string to be interpreted by the command processor rather than executing a program directly. The `args.args` value is not quoted or escaped at all. Shell metacharacters such as `&`, `|`, redirection operators, and command-grouping syntax can therefore append or replace commands. The fallback behavior for `args.app` also permits an arbitrary caller-supplied value to enter the quoted command string. Embedded quotation marks can terminate that boundary and introduce additional shell syntax. ### Attack Path 1. An attacker, untrusted prompt, or compromised caller controls the `app` or `args` parameter of `desktop_launch_app`. 2. The value is substituted into the `start` command without shell-safe encoding. 3. A value containing command separators, such as an argument beginning with `&`, changes the command interpreted by `cmd.exe`. 4. `subprocess.Popen(..., shell=True)` exe ...[truncated 575 chars]
Remediation
## Remediation Suggestions - Remove `shell=True` and invoke the executable with a structured argument list. - Resolve supported application aliases to fixed executable paths. - If custom applications must be supported, require an absolute path and validate it against an explicit allowlist of permitted directories or executables. - Parse application arguments into a list with a Windows-aware parser rather than concatenating them into a command. - Reject shell metacharacters when the requested operation does not legitimately require shell syntax. - Require explicit user approval before launching arbitrary executable paths. - Run application-launch operations in a restricted, non-administrative security context.

T09 · Insecure Skill Coding Practices

Error
Location
rpa.py:309
Finding
PowerShell Injection in Clipboard and Window Operations## Vulnerability Details **File Locations**: `rpa.py:309-317`, `rpa.py:412-420`, and `rpa.py:424-445` **Vulnerability Type**: PowerShell source-code injection **Risk Level**: High ### Vulnerable Code ```python def cmd_clipboard_set(args): """设置剪贴板""" try: result = subprocess.run( ['powershell', '-Command', f'Set-Clipboard -Value "{args.text}"'], capture_output=True, text=True, timeout=5 ) return {"status": "ok", "message": "剪贴板已设置"} except Exception as e: return {"status": "error", "message": str(e)} ``` ```python def cmd_window_activate(args): """激活窗口""" try: result = subprocess.run( ['powershell', '-Command', f'(New-Object -ComObject WScript.Shell).AppActivate("{args.title_pattern}")'], capture_output=True, text=True, timeout=5 ) return {"status": "ok", "title_pattern": args.title_pattern} except Exception as e: return {"status": "error", "message": str(e)} ``` ```python def cmd_find_window(args): """查找窗口""" try: title_filter = args.title_contains or "" result = subprocess.run( ['powershell', '-Command', f'Get-Process | Where-Object {{$_.MainWindowTitle -like "*{title_filter}*"}} | Select-Object ProcessName, MainWindowTitle, Id | ConvertTo-Json'], capture_output=True, text=True, timeout=10 ) if result.returncode == 0 and result.stdout.strip(): windows = json.loads(result.stdout) if not isinstance(windows, list): windows = [windows] return { "status": "ok", "windows": [ {"process": w.get("ProcessName"), "title": w.get("MainWindowTitle"), "pid": w.get("Id")} for w in windows ] ...[truncated 1947 chars]
Remediation
## Remediation Suggestions - Do not construct PowerShell source by interpolating user input. - Pass data through stdin, environment variables, or a safely encoded parameter channel. - For clipboard operations, prefer `pyperclip.copy(args.text)` or another direct API that does not invoke PowerShell. - For window operations, use Windows APIs or `pywinauto` rather than dynamically generated scripts. - If PowerShell is unavoidable, use a fixed script with declared parameters and bind caller data as parameter values. - Validate window filters and reject control characters, quotation marks, script-block delimiters, and statement separators. - Add regression tests using quotation marks, subexpressions, semicolons, and newline characters. - Treat all affected operations as sensitive until the injection surfaces are removed.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
rpa.py:335
Finding
Unrestricted Shell Execution Without Enforced Authorization## Vulnerability Details **File Locations**: `rpa.py:335-360` and `rpa.py:450-466`; related configuration at `skill.json:38-40` and `skill.json:96-106` **Vulnerability Type**: Missing authorization and least-privilege enforcement for arbitrary command execution **Risk Level**: High ### Vulnerable Code ```python def cmd_shell(args): """执行 Shell 命令""" shell_type = args.shell_type or "powershell" try: if shell_type == "powershell": result = subprocess.run( ['powershell', '-NoProfile', '-Command', args.command], capture_output=True, text=True, timeout=60 ) else: result = subprocess.run( ['cmd', '/c', args.command], capture_output=True, text=True, timeout=60 ) return { "status": "ok", "stdout": result.stdout, "stderr": result.stderr, "exit_code": result.returncode } except subprocess.TimeoutExpired: return {"status": "error", "message": "命令执行超时"} except Exception as e: return {"status": "error", "message": str(e)} ``` ```python def cmd_run_app(args): """运行命令""" try: result = subprocess.run( args.command, shell=True, capture_output=True, text=True, timeout=60 ) return { "status": "ok", "stdout": result.stdout, "stderr": result.stderr, "exit_code": result.returncode } except subprocess.TimeoutExpired: return {"status": "error", "message": "命令执行超时"} except Exception as e: return {"status": "error", "message": str(e)} ``` ```json "security": { "permissions": ["screen_capture", "keyboard_input", "mouse_input", "clipboard_access", "shell_execution"] ...[truncated 1893 chars]
Remediation
## Remediation Suggestions - Remove generic command execution if it is not indispensable to desktop automation. - Make user approval mandatory rather than recommended for every invocation of both `desktop_shell` and `desktop_run_app`. - Add `desktop_run_app` to every applicable sensitive-operation list. - Require a short-lived, operation-specific authorization token that binds approval to the exact command and arguments. - Prefer narrowly scoped tools for required administrative actions instead of exposing a generic shell. - Apply an explicit allowlist of executable paths, command names, and permitted arguments. - Execute commands using a restricted, non-administrative account or a hardened sandbox. - Restrict network access, filesystem access, child-process creation, and access to user credentials where the platform permits. - Record tamper-resistant audit logs containing the approver, exact command, execution time, exit status, and affected working directory.

T09 · Insecure Skill Coding Practices

Error
Location
skill.json:96
Finding
Unsafe Tool Command Templates Permit Pre-Execution Shell Injection## Vulnerability Details **File Location**: `skill.json:96-106` **Vulnerability Type**: Unsafe command-template interpolation **Risk Level**: High ### Vulnerable Code ```json { "name": "desktop_run_app", "description": "运行命令", "sensitive": true, "script": "scripts/rpa.py run_app --command {command}" }, { "name": "desktop_shell", "description": "执行 Shell 命令", "sensitive": true, "script": "scripts/rpa.py shell --command \"{command}\" --shell_type {shell_type}" } ``` Other tool templates use the same interpolation pattern, including: ```json { "name": "desktop_keyboard_type", "description": "键盘输入文本", "script": "scripts/rpa.py keyboard_type --text \"{text}\"" } ``` ```json { "name": "desktop_clipboard_set", "description": "设置剪贴板内容", "script": "scripts/rpa.py clipboard_set --text \"{text}\"" } ``` ### Technical Analysis Tool arguments are represented as placeholders inside command strings rather than as structured argument arrays. No escaping contract is defined for these placeholders. Quoting a placeholder with double quotes is insufficient because a caller-provided quotation mark can terminate the argument, after which shell metacharacters may be interpreted. The exact exploitability depends on how the host executes the `script` field. If it performs textual substitution and passes the result through a shell, injection occurs before `rpa.py` starts. Consequently, even Python functions that otherwise use argument arrays can be bypassed at the manifest-launch layer. The unquoted `{command}` in `desktop_run_app` is especially exposed, while quoted fields such as `{text}` remain vulnerable if quotation marks are not escaped by the host. ### Attack Path 1. An attacker controls a tool parameter inserted into `{command}`, `{text}`, or another placeholder. 2. The host substitutes the value into the `script` string. 3. The value terminates its intended ar ...[truncated 648 chars]
Remediation
## Remediation Suggestions - Replace command-string templates with structured executable and argument arrays. - Define parameter schemas with explicit types, maximum lengths, and allowed values. - Ensure the host invokes Python directly without an intermediate shell. - If legacy string templates are unavoidable, use operating-system-specific argument quoting implemented by the launcher rather than manual quotation marks. - Restrict fields such as `shell_type`, mouse buttons, and executable aliases to fixed enumerations. - Add integration tests proving that quotation marks, ampersands, pipes, redirection characters, percent expansion, and newlines remain literal argument content. - Apply approval and logging before template expansion and again before process creation for command-execution tools.

T08 · Insecure Dependencies

Warning
Location
skill.json:11
Finding
Unpinned Python Dependencies Create Supply-Chain Exposure## Vulnerability Details **File Location**: `skill.json:11-29` **Vulnerability Type**: Unpinned and unhashed third-party dependencies **Risk Level**: Medium ### Vulnerable Code ```json "install": [ { "id": "pip-pyautogui", "kind": "pip", "package": "pyautogui pillow", "label": "Install PyAutoGUI for mouse/keyboard automation" }, { "id": "pip-pywinauto", "kind": "pip", "package": "pywinauto", "label": "Install PyWinAuto for Windows UI Automation" }, { "id": "pip-pyperclip", "kind": "pip", "package": "pyperclip", "label": "Install Pyperclip for clipboard operations" } ] ``` The README also recommends: ```bash pip install pyautogui pillow pywinauto pyperclip ``` ### Technical Analysis The installation configuration specifies package names without exact versions, hashes, or a lockfile. Every installation can therefore resolve a different release and transitive dependency set. The observed package names are conventional, and the audited project does not configure a suspicious package index or remote payload source. Nevertheless, mutable dependency resolution means a compromised future release, malicious transitive update, or index-resolution change could introduce code that was never part of this audit. Python packages may execute code during installation and are imported into a process with screen, keyboard, mouse, and clipboard access, increasing the consequences of a dependency compromise. ### Attack Path 1. A dependency or one of its transitive dependencies publishes a compromised release, or package resolution is redirected to an untrusted index. 2. A user follows the manifest or README installation instructions. 3. `pip` resolves the mutable latest-compatible package set. 4. Malicious code runs during installation or when the package is imported. 5. The compromised dependency receives the permissions available to ...[truncated 484 chars]
Remediation
## Remediation Suggestions - Pin every direct dependency to an exact reviewed version. - Generate and commit a lockfile that includes transitive dependencies. - Require cryptographic hashes during installation, such as through a hash-locked requirements file and `pip --require-hashes`. - Use only the official or an organization-controlled Python package index. - Review dependency release notes and security advisories before updating pins. - Scan packages and their transitive dependencies in CI. - Build and distribute verified artifacts from a controlled pipeline instead of resolving mutable dependencies on end-user systems. - Run dependency installation with minimal privileges and isolate build-time network access where practical.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (33)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
try:
        if args.args:
            subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True)
        else:
            subprocess.Popen(f'start "" "{app_path}"', shell=True)
Confidence
99% confidence
Finding
This duplicate finding correctly identifies the same exploit path at line 264: interpolated args plus shell=True in the launcher. The skill context makes it especially dangerous because launch is expected to be a routine automation action and may receive untrusted task-derived parameters.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
try:
        if args.args:
            subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True)
        else:
            subprocess.Popen(f'start "" "{app_path}"', shell=True)
Confidence
99% confidence
Finding
This duplicate finding correctly identifies the same exploit path at line 264: interpolated args plus shell=True in the launcher. The skill context makes it especially dangerous because launch is expected to be a routine automation action and may receive untrusted task-derived parameters.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if args.args:
            subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True)
        else:
            subprocess.Popen(f'start "" "{app_path}"', shell=True)
        
        return {"status": "ok", "app": args.app, "path": app_path}
    except Exception as e:
Confidence
90% confidence
Finding
This duplicate finding points to the no-args branch still relying on shell=True. While not as immediately injectable as the args branch, the execution model is still broader and riskier than needed for simple app startup.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if args.args:
            subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True)
        else:
            subprocess.Popen(f'start "" "{app_path}"', shell=True)
        
        return {"status": "ok", "app": args.app, "path": app_path}
    except Exception as e:
Confidence
90% confidence
Finding
This duplicate finding points to the no-args branch still relying on shell=True. While not as immediately injectable as the args branch, the execution model is still broader and riskier than needed for simple app startup.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill intentionally includes unrestricted shell execution unrelated to narrow desktop UI automation. In an agent environment this becomes a universal escape hatch for arbitrary system actions, making any prompt injection or misuse far more damaging.

Missing User Warnings

High
Confidence
99% confidence
Finding
Arbitrary shell execution is exposed without any warning or approval gate, enabling destructive or stealthy host actions. The lack of user-facing safety controls makes misuse and prompt-injection-driven abuse substantially more likely and more severe.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
run_app is a second arbitrary execution pathway using shell=True, duplicating and widening the attack surface. Multiple generic execution routes make policy enforcement harder and allow bypass if one path is later restricted.

Missing User Warnings

High
Confidence
99% confidence
Finding
This second arbitrary command-execution path uses shell=True and lacks any warning or consent boundary. It allows complete host compromise or destructive system actions while appearing as a normal automation helper.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def cmd_run_app(args):
    """运行命令"""
    try:
        result = subprocess.run(
            args.command,
            shell=True,
            capture_output=True,
Confidence
99% confidence
Finding
Passing attacker-controlled command text to subprocess.run with shell=True grants unrestricted shell execution. In an agent skill, this is direct parameter abuse that collapses the distinction between automation and arbitrary code execution.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README advertises screenshot capture, clipboard access, and shell command execution without clearly warning about privacy exposure, credential leakage, or destructive system actions. In a desktop RPA skill, these capabilities are highly sensitive because they can access visible data, copy secrets, and execute arbitrary commands on the host.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
When enabled:
1. Sensitive operations will request user confirmation before execution
2. User can approve, deny, or modify parameters
3. Whitelist can be configured to skip approval for trusted operations

## Sandbox Support
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This markdown file contains user-facing instructions and examples only in Chinese, but the skill is not documented as China-specific or otherwise justified as locale-bound. That can violate language/locale policy because it effectively forces a specific language without user opt-in.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The screenshot feature captures the desktop and writes an image to disk without any built-in disclosure, confirmation, or retention control. Screenshots can expose secrets, personal data, internal documents, or security prompts, especially in unattended agent use.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        if args.args:
            subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True)
        else:
            subprocess.Popen(f'start "" "{app_path}"', shell=True)
Confidence
99% confidence
Finding
The launch command concatenates untrusted args.args into a shell command and invokes it with shell=True. An attacker can append command separators or shell syntax to execute arbitrary commands under the agent's privileges.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.args:
            subprocess.Popen(f'start "" "{app_path}" {args.args}', shell=True)
        else:
            subprocess.Popen(f'start "" "{app_path}"', shell=True)
        
        return {"status": "ok", "app": args.app, "path": app_path}
    except Exception as e:
Confidence
72% confidence
Finding
This branch still uses shell=True, but only with a quoted application path and no additional user-controlled arguments in the constructed string. That is less directly exploitable than line 264, though it still expands attack surface and could become unsafe if app_path is influenced by unexpected input or shell parsing edge cases.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def cmd_window_list(args):
    """列出窗口"""
    try:
        result = subprocess.run(
            ['powershell', '-Command', 
             'Get-Process | Where-Object {$_.MainWindowTitle} | Select-Object ProcessName, MainWindowTitle, Id | ConvertTo-Json'],
            capture_output=True, text=True, timeout=10
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
Reading the clipboard without a user-facing warning exposes potentially sensitive transient data such as passwords, API keys, tokens, or copied business content. In agent-driven workflows, this can silently exfiltrate data the user never intended to share with the tool.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def cmd_clipboard_get(args):
    """获取剪贴板"""
    try:
        result = subprocess.run(
            ['powershell', '-Command', 'Get-Clipboard'],
            capture_output=True, text=True, timeout=5
        )
Confidence
86% confidence
Finding
This command reads and returns the full clipboard without any access control, minimization, or disclosure. In an agent skill context, clipboard contents commonly contain passwords, tokens, personal data, or copied secrets, so this becomes a data-exfiltration primitive even though there is no command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def cmd_clipboard_set(args):
    """设置剪贴板"""
    try:
        result = subprocess.run(
            ['powershell', '-Command', f'Set-Clipboard -Value "{args.text}"'],
            capture_output=True, text=True, timeout=5
        )
Confidence
98% confidence
Finding
User-controlled text is interpolated directly into a PowerShell command string: Set-Clipboard -Value "{args.text}". An attacker can inject quotes and PowerShell metacharacters to break out of the string and execute arbitrary commands.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        if shell_type == "powershell":
            result = subprocess.run(
                ['powershell', '-NoProfile', '-Command', args.command],
                capture_output=True, text=True, timeout=60
            )
Confidence
99% confidence
Finding
This exposes arbitrary PowerShell execution by passing user input directly to powershell -Command. In the context of an agent-accessible RPA skill, this is a full remote command-execution capability and can be used for persistence, data theft, or lateral movement.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
capture_output=True, text=True, timeout=60
            )
        else:
            result = subprocess.run(
                ['cmd', '/c', args.command],
                capture_output=True, text=True, timeout=60
            )
Confidence
99% confidence
Finding
This executes attacker-controlled input through cmd /c, enabling arbitrary Windows command execution. Because the skill is intended for desktop automation, this dramatically increases risk beyond normal UI control and provides a direct system compromise path.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
get_state aggregates environment details, mouse position, screen size, active window metadata, and optional screenshot capture into one call. In an agent skill this broadens reconnaissance and privacy exposure, allowing collection of sensitive desktop context not strictly necessary for many RPA tasks.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
Desktop state collection can reveal active-window titles, runtime environment details, and optionally a screenshot, all without clear disclosure. This creates privacy and reconnaissance risk disproportionate to simple automation support.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 获取活动窗口
    try:
        result = subprocess.run(
            ['powershell', '-Command', 
             '(Get-Process | Where-Object {$_.MainWindowTitle} | Select-Object -First 1 ProcessName, MainWindowTitle, Id) | ConvertTo-Json'],
            capture_output=True, text=True, timeout=5
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.