Back to skill

Security audit

visual-rpa-skill

Security checks for vulnerabilities and agentic risk

Overview

This desktop automation skill is coherent, but it can control any visible app while sending and saving screen captures without enough confirmation or scoping.

Review carefully before installing. Use this only when you are comfortable with visible desktop contents being sent to DashScope and saved under ./rpa_logs, close sensitive windows first, prefer DASHSCOPE_API_KEY over --api-key, and require explicit human confirmation before messaging, submitting forms, deleting data, changing settings, or entering credentials.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/visual_rpa.py:217
Finding
Unredacted full-screen screenshots are transmitted to an external vision API## Vulnerability Details **File Location**: `scripts/visual_rpa.py`, lines 97–114, 217–237, 475–481, and 553–560 **Vulnerability Type**: External disclosure of sensitive screen content **Risk Level**: High ### Vulnerable Code ```python def capture_full(self) -> Image.Image: raw = self.sct.grab(self.sct.monitors[1]) return Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX") ``` ```python def to_base64(self, img: Image.Image, fmt: str = "JPEG", quality: int = 85) -> str: buf = io.BytesIO() if fmt == "JPEG": img.save(buf, format=fmt, quality=quality) else: img.save(buf, format=fmt) return base64.b64encode(buf.getvalue()).decode() ``` ```python class QwenVision: BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1" def __init__(self, model: str = "qwen-vl-max-latest", api_key: str = ""): self.client = OpenAI( api_key=api_key or os.getenv("DASHSCOPE_API_KEY", ""), base_url=self.BASE_URL, ) self.model = model def _call(self, system: str, img_b64: str, user_text: str, media_type: str = "image/jpeg", max_tokens: int = 1024) -> str: resp = self.client.chat.completions.create( model=self.model, max_tokens=max_tokens, messages=[ {"role": "system", "content": system}, { "role": "user", "content": [ {"type": "image_url", "image_url": { "url": f"data:{media_type};base64,{img_b64}"}}, {"type": "text", "text": user_text}, ], }, ], ) ``` ```python full_img = self.cap.capture_full() thumb = self.cap.resize(full_img, self.thumbnail_width) thumb_b64 = self.cap.to_base64(thumb) self.cap.save(thumb, f"step{s ...[truncated 2421 chars]
Remediation
## Remediation Suggestions - Clearly disclose that screenshots are transmitted to DashScope and require explicit informed consent before the first transmission. - Capture only the target application window or the smallest necessary region instead of the complete monitor. - Redact password fields, authentication codes, notifications, clipboard managers, and unrelated application windows. - Add a preview mode showing exactly what will be transmitted. - Provide an offline or locally hosted vision-model option for sensitive workflows. - Disable verification screenshots where they are not required. - Document the external endpoint, provider retention policy, processing region, and privacy implications. - Fail safely when a target region cannot be isolated rather than falling back to transmitting the whole display.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/visual_rpa.py:36
Finding
Sensitive screenshots are persistently stored without access controls or retention limits## Vulnerability Details **File Location**: `scripts/visual_rpa.py`, lines 36–44, 116–120, 478, 505, and 556 **Vulnerability Type**: Insecure storage of sensitive screen content **Risk Level**: Medium ### Vulnerable Code ```python LOG_DIR = Path("./rpa_logs") LOG_DIR.mkdir(exist_ok=True) logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.StreamHandler(), logging.FileHandler(LOG_DIR / "rpa.log", encoding="utf-8"), ], ) ``` ```python def save(self, img: Image.Image, tag: str = "") -> str: ts = datetime.now().strftime("%Y%m%d_%H%M%S_%f") path = LOG_DIR / f"ss_{tag}_{ts}.png" img.save(str(path)) return str(path) ``` ```python self.cap.save(thumb, f"step{step_index}_thumb") ``` ```python self.cap.save(crop, f"step{step_index}_crop") ``` ```python self.cap.save(after_thumb, f"step{step_index}_after") ``` ### Technical Analysis The Skill automatically saves initial screenshots, detailed crops, and post-action screenshots under a relative `./rpa_logs/` directory. This occurs during ordinary operation rather than only when an explicit diagnostic mode is enabled. The directory is created without an explicit restrictive permission mode. The implementation also provides no encryption, retention period, cleanup routine, storage quota, redaction, or user opt-out. Multiple retries can produce additional copies of the same sensitive screen state. Because the path is relative to the current working directory, screenshots may also be written into shared workspaces, synchronized folders, project directories, or locations included in backups. ### Attack Path 1. The user runs an automation task while confidential information is visible. 2. The Skill saves thumbnails, target crops, and post-action images in `rpa_logs`. 3. The files remain after the automation session ends. 4. Another l ...[truncated 678 chars]
Remediation
## Remediation Suggestions - Disable screenshot persistence by default. - Require an explicit `--debug-screenshots` option before writing images. - Store diagnostic files in a private per-user directory with restrictive permissions. - Reject shared or world-readable storage locations. - Redact sensitive interface regions before saving. - Implement configurable retention limits and automatic cleanup. - Apply file-count and total-size limits to prevent unbounded accumulation. - Warn users when diagnostic screenshots are enabled. - Exclude the log directory from source control, synchronization, and routine backups where appropriate.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/visual_rpa.py:650
Finding
API credentials can be exposed through command-line arguments## Vulnerability Details **File Location**: `scripts/visual_rpa.py`, lines 650–659 **Vulnerability Type**: Insecure secret handling **Risk Level**: Medium ### Vulnerable Code ```python p.add_argument("--mode", choices=["interactive", "task"], default="interactive") p.add_argument("--model", default="qwen-vl-max-latest") p.add_argument("--api-key", default="") p.add_argument("--no-verify", action="store_true") p.add_argument("--task", nargs="+") args = p.parse_args() rpa = VisualRPA( model=args.model, api_key=args.api_key, verify_actions=not args.no_verify, ) ``` ```python self.client = OpenAI( api_key=api_key or os.getenv("DASHSCOPE_API_KEY", ""), base_url=self.BASE_URL, ) ``` ### Technical Analysis The implementation supports supplying the DashScope API key through `--api-key`. Secrets passed as command-line arguments may be recorded in shell history, terminal logs, process-monitoring systems, crash reports, or automation logs. On systems where process arguments are visible to other local principals, the credential may also be observed while the process is running. The environment-variable fallback is safer than a command-line argument, although environment variables also require appropriate process isolation. No evidence was found that the code intentionally logs the API key. ### Attack Path 1. A user invokes the script with `--api-key` followed by a valid credential. 2. The complete command is retained in shell history or exposed through process inspection. 3. Another local user, monitoring process, or log reader retrieves the key. 4. The attacker uses the credential against the associated DashScope account. 5. The attacker consumes API quota or accesses services permitted by that credential. ### Impact Assessment The exposed privilege is limited to the permissions assigned to the compromised DashScope API key. Potential effects include unauthorized API usage, q ...[truncated 228 chars]
Remediation
## Remediation Suggestions - Remove the `--api-key` command-line option. - Prefer a protected environment variable, operating-system keyring, or dedicated secret manager. - If interactive entry is required, read the key through a non-echoing prompt or standard input. - Document that credentials must not be included in shell commands, task descriptions, or logs. - Use narrowly scoped credentials and rotate any key previously supplied through command-line arguments. - Ensure diagnostic and exception handlers never serialize client configuration containing the key.

T08 · Insecure Dependencies

Note
Location
scripts/visual_rpa.py:11
Finding
Unpinned third-party dependencies create a mutable supply-chain risk## Vulnerability Details **File Location**: `scripts/visual_rpa.py`, line 11 **Vulnerability Type**: Unpinned runtime dependencies **Risk Level**: Low ### Vulnerable Code ```text pip install mss pyautogui openai pillow ``` ### Technical Analysis The installation instruction requests four packages without fixed versions or integrity hashes. Consequently, identical installation commands can resolve to different code over time. The package names are consistent with the Skill's stated functionality, and the audited project does not specify an untrusted package index, suspicious download URL, or known typosquatted name. The risk is therefore the mutable dependency set rather than evidence of a deliberately malicious dependency. These packages execute with the same local privileges as the Skill and include functionality related to screen capture, input automation, image processing, and network access. ### Attack Path 1. A user follows the unpinned installation instruction. 2. The package resolver downloads the latest versions available at that time. 3. A dependency or transitive dependency has been compromised, replaced, or changed incompatibly. 4. Malicious or unsafe package code executes during installation or import. 5. The dependency gains access to the Skill process, including its screen-capture capability and API credential environment. ### Impact Assessment A compromised dependency could execute arbitrary code with the invoking user's privileges. This could expose screen contents, API credentials, local files accessible to the user, clipboard data, and the ability to control desktop input. No actual compromised package was established during this static audit; this finding concerns the absence of reproducible dependency controls.
Remediation
## Remediation Suggestions - Add a reviewed requirements or lock file with exact versions. - Use integrity hashes for downloaded distributions. - Pin transitive dependencies where the chosen package-management workflow permits it. - Install dependencies in an isolated virtual environment. - Use a trusted package index and prevent silent fallback to untrusted indexes. - Add automated dependency vulnerability and provenance scanning. - Review and deliberately update locked versions on a controlled schedule.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/visual_rpa.py:366
Finding
Model-selected desktop actions execute without risk-sensitive confirmation gates## Vulnerability Details **File Location**: `SKILL.md`, line 8; `scripts/visual_rpa.py`, lines 366–390 and 584–598 **Vulnerability Type**: Unsafe automatic execution of high-impact UI actions **Risk Level**: Medium ### Vulnerable Code ```text Auto-execute all steps without waiting for user confirmation between steps. ``` ```python def execute(self, plan: ActionPlan): action = plan.action.lower().replace(" ", "_") logger.info(f"execute: {action} @ ({plan.x}, {plan.y})") if action == "click": pyautogui.click(plan.x, plan.y) elif action == "double_click": pyautogui.doubleClick(plan.x, plan.y) elif action == "right_click": pyautogui.rightClick(plan.x, plan.y) elif action == "type": if plan.x and plan.y: pyautogui.click(plan.x, plan.y) time.sleep(0.5) self._type_text(plan.text) elif action == "hotkey": keys = [k.strip() for k in plan.keys.split("+")] pyautogui.hotkey(*keys) elif action == "scroll": amt = plan.scroll_amount if plan.scroll_direction == "down" else -plan.scroll_amount pyautogui.scroll(amt, x=plan.x, y=plan.y) elif action == "wait": time.sleep(2) else: pyautogui.click(plan.x, plan.y) ``` ```python for i, step in enumerate(all_steps): r = self.execute_step(step, step_index=i) results.append(r) self.history.append(r) logger.info(f"step {i}: {'OK' if r.success else 'FAIL'} | {step}") if not r.success and stop_on_failure: break ``` ### Technical Analysis The remote vision model selects the action type, coordinates, text, and hotkeys. The resulting `ActionPlan` is passed directly to PyAutoGUI. The Skill does not classify sensitive actions, constrain operations to an approved application, preview the action plan, or request confirmation before irreversible events. High-impact actions can ...[truncated 1628 chars]
Remediation
## Remediation Suggestions - Require explicit confirmation before sending messages, submitting forms, purchasing, deleting data, changing permissions, entering credentials, or accepting security prompts. - Display the proposed action, target application, target element, coordinates, and text before sensitive execution. - Add application and action allowlists scoped to the user's request. - Validate that the foreground application is the expected target immediately before execution. - Treat unknown action values as errors instead of falling back to a click. - Do not automatically retry potentially non-idempotent actions. - Add a dry-run mode that visualizes intended clicks without performing them. - Detect suspicious on-screen instructions and reduce reliance on prompt-only defenses against visual prompt injection. - Preserve an easily accessible emergency stop mechanism and document it clearly.
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Vague Triggers

High
Confidence
96% confidence
Finding
The activation description is extremely broad and matches many ordinary user requests involving apps, typing, clicking, messaging, or browsing. Because the skill performs real desktop actions through visual automation, broad triggering can cause the agent to select it for sensitive or ambiguous requests and operate external applications without sufficiently narrow gating.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill explicitly instructs auto-execution of desktop steps without waiting for user confirmation, yet provides no prominent warning about the risk of unintended clicks, data entry, message sending, or destructive actions. In a visual RPA context, misidentification of UI elements or state can directly trigger irreversible actions in arbitrary applications.

Ssd 3

High
Confidence
97% confidence
Finding
The skill logs screenshots locally and also transmits screenshots plus step instructions to the model, creating a strong data-leakage path for whatever is visible on screen or written in instructions. In a visual RPA tool this is especially dangerous because users may automate messaging, documents, account pages, and other sensitive workflows where incidental capture is likely.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill uploads screenshots to a remote vision service without any explicit user-facing warning or confirmation. Because the capture is of the live desktop, this can expose highly sensitive information from unrelated windows, notifications, chats, or documents during ordinary use.

Ssd 3

High
Confidence
96% confidence
Finding
The task flow forwards arbitrary natural-language instructions and screenshots to the model, allowing users or upstream agents to request actions that summarize, reveal, or extract sensitive visible data. Because the tool combines unrestricted prompt forwarding with full-screen capture and remote inference, it materially increases the chance of unintentional exfiltration of secrets or private content.

Missing User Warnings

High
Confidence
98% confidence
Finding
The verification stage sends before/after screenshots to the remote API, doubling the amount of exposed screen content without separate disclosure. This broadens the privacy impact because more UI state, user activity, and application contents are transmitted than is necessary for a minimally transparent automation tool.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes shell execution and depends on environment variables, but it declares no explicit tool scope or permissions boundary. That omission increases the chance the agent can invoke this powerful desktop automation skill in broader contexts than intended, with little policy friction or visibility.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Visual RPA Desktop Automation

> Auto-execute all steps without waiting for user confirmation between steps.

Desktop automation via screen capture + Qwen vision model (Qwen-VL). No DOM or accessibility API needed.
Confidence
97% confidence
Finding
The skill's instruction to auto-execute all steps without confirmation delegates meaningful decision-making to the automation workflow, including decomposition of compound tasks into atomic actions. In a desktop-control skill, this materially raises the chance of unsafe autonomous behavior because the system may interpret intent, sequence actions, and continue despite ambiguity or changing screen state.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
python "$env:TAXBOT_ROOT/skills/visual-rpa/scripts/visual_rpa.py" --mode task --task "click Chrome browser" "type baidu.com in address bar and press enter" "type weather in search box" "click search button"
```

### Skip verification (faster)

```
python "$env:TAXBOT_ROOT/skills/visual-rpa/scripts/visual_rpa.py" --mode task --no-verify --task "click to open Calculator"
Confidence
94% confidence
Finding
The documented '--no-verify' mode disables post-action verification in a system that relies on visual inference to locate and manipulate UI elements. That creates a clear path for autonomous actions to proceed even when the model clicks the wrong target, causing unintended commands, disclosure, or destructive operations on the user's desktop.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill sends screenshots of the user's desktop and task instructions to a third-party vision API, which exceeds a simple local desktop automation expectation and can expose sensitive on-screen data. In an RPA skill, this is especially dangerous because full-screen captures may contain messages, credentials, documents, or unrelated applications visible at the time of execution.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The code performs mouse and keyboard automation on the local system without an explicit safety warning, confirmation gate, or constrained permission model. In an RPA context this is inherently risky because the agent can click unintended targets, send messages, alter files, or trigger destructive actions if the visual model misidentifies UI elements.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The text-entry path modifies the system clipboard and invokes platform clipboard utilities, which affects user data outside the immediate automation action. In this context, clipboard replacement can overwrite sensitive copied content and may leak or retain user-provided text in system clipboard history or other clipboard-monitoring tools.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Clipboard manipulation and platform subprocess use for pasting occur without explicit disclosure to the user. This is dangerous in desktop automation because it silently changes a global OS resource, can destroy the user's copied data, and may leave sensitive task text accessible to other applications or clipboard history.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
import subprocess, platform
        system = platform.system()
        if system == "Darwin":
            subprocess.run(["pbcopy"], input=text.encode("utf-8"), check=True)
            pyautogui.hotkey("command", "v")
        elif system == "Windows":
            import ctypes
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
user32.CloseClipboard()
            pyautogui.hotkey("ctrl", "v")
        else:
            subprocess.run(["xclip", "-selection", "clipboard"],
                           input=text.encode("utf-8"), check=True)
            pyautogui.hotkey("ctrl", "v")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The module docstring and user-facing prompts are presented in Chinese, and the interactive interface also uses Chinese strings, effectively imposing a language choice on users. There is no indication that this is a region-specific tool or that users can opt into another language.

Description-Behavior Mismatch

Low
Confidence
92% confidence
Finding
The code persistently stores logs and screenshots to local disk without stating this behavior in the manifest description. Even if intended for debugging, saved UI images can retain sensitive information long after task completion and broaden exposure beyond the user’s expectation for a desktop-control skill.