Back to skill

Security audit

dekstop-control-linux

Security checks for vulnerabilities and agentic risk

Overview

This Linux desktop automation skill is coherent, but its advertised approval mode does not cover several sensitive actions like screenshots, screen recording, clipboard access, OCR, and some desktop manipulation.

Review before installing. This skill gives an agent practical control over a Linux desktop session and can capture visible screen contents, OCR text, read/write clipboard data, record video, launch apps, and save files. Use it only in a dedicated, non-sensitive desktop session, avoid disabling approval mode, and treat screenshots or recordings as sensitive data.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
__init__.py:149
Finding

Approval Mode Does Not Protect Multiple Sensitive Desktop Operations

Content
View full analysis
None: if x is not None and y is not None: pyautogui.moveTo(x, y) if direction == "vertical": pyautogui.scroll(clicks) else: pyautogui.hscroll(clicks) ``` ```python def drag_drop(self, from_x: int, from_y: int, to_x: int, to_y: int, duration: float = 0.5) -> None: """Drag from (x1, y1) to (x2, y2).""" pyautogui.moveTo(from_x, from_y, duration=0.2) pyautogui.mouseDown() pyautogui.moveTo(to_x, to_y, duration=duration) pyautogui.mouseUp() def drag_file_to_app(self, file_path: str, target_x: int, target_y: int) -> None: """Drag a file to a specific position (e.g., drop file to app).""" self.drag_drop(0, 0, target_x, target_y, duration=1) ``` ```python def screenshot(self, region: Optional[Tuple[int, int, int, int]] = None, filename: Optional[str] = None): img = pyautogui.screenshot(region=region) if filename: img.save(filename) else: return img def screenshot_to(self, filename: str, region: Optional[Tuple[int, int, int, int]] = None) -> str: """Take a screenshot and save to filename. Returns filename.""" self.screenshot(region=region, filename=filename) return filename ``` ```python def copy_to_clipboard(self, text: str) -> None: try: import pyperclip pyperclip.copy(text) except Exception as e: logger.error(f"Clipboard copy error: {e}") def get_from_clipboard(self) -> Optional[str]: try: import pyperclip return pyperclip.paste() except Exception as e: logger.error(f"Clipboard paste error: {e}") return None ``` ### Technical Ana ...[truncated 2089 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
__init__.py:72
Finding

Automatic X11 Display Selection Can Target an Unintended Desktop Session

Content
View full analysis
None: session = os.environ.get("XDG_SESSION_TYPE", "unknown") display = os.environ.get("DISPLAY") wayland = os.environ.get("WAYLAND_DISPLAY") if not display and not wayland: # Attempt auto-detect X11 DISPLAY via /tmp/.X11-unix detected = self._auto_detect_display() if detected: os.environ["DISPLAY"] = detected display = detected logger.info(f"Auto-detected DISPLAY={detected}") else: logger.warning("No DISPLAY/WAYLAND_DISPLAY detected. GUI automation may fail.") if session == "wayland": logger.warning( "Wayland session detected. Many distros restrict input control/screenshot; " "X11 is recommended for full functionality." ) def _auto_detect_display(self) -> Optional[str]: try: if os.path.isdir("/tmp/.X11-unix"): for name in sorted(os.listdir("/tmp/.X11-unix")): if name.startswith("X"): return f":{name[1:]}" except Exception: return None return None ``` ### Technical Analysis When neither `DISPLAY` nor `WAYLAND_DISPLAY` is configured, the code enumerates the globally visible `/tmp/.X11-unix` directory and selects the first socket whose name begins with `X`. It does not verify: - Which user owns the selected graphical session. - Whether the session belongs to the invoking process or user. - Whether appropriate Xauthority credentials are available. - Whether multiple displays exist and selection is ambiguous. - Whether the user approved connecting to the selected display. The selected value is written into `os.environ["DISPLAY"]`, after which PyAutoGUI, FFmpeg, `wmctrl`, and `xdotool` operations may target that session. X11 ...[truncated 1564 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
__init__.py:692
Finding

Screen Recording Accepts Unrestricted FFmpeg Output Targets and Overwrites Existing Files

Content
View full analysis
str: """Record screen using ffmpeg. Requires ffmpeg installed.""" if display is None: display = os.environ.get("DISPLAY", ":0") if resolution is None: resolution = f"{self.screen_width}x{self.screen_height}" cmd = [ "ffmpeg", "-y", "-f", "x11grab", "-video_size", resolution, "-i", f"{display}.0", "-t", str(seconds), "-r", str(fps), output_path ] subprocess.run(cmd, check=True) return output_path ``` ### Technical Analysis The method passes `output_path` directly to FFmpeg and enables unconditional overwrite behavior through `-y`. Although the command correctly uses an argument array and is not vulnerable to shell metacharacter injection, FFmpeg performs its own interpretation of output targets. Depending on the installed FFmpeg build and supported protocols, an output value may identify either a local file or a protocol-based destination. The method does not restrict output to an approved directory, reject URI schemes, ensure that the destination is a regular file, or protect existing files from overwrite. It also does not request approval before capturing the display. The caller can additionally provide the display and resolution parameters without validation. Invalid values may cause failures or excessive resource consumption, although the principal security concern is the unrestricted destination for sensitive screen content. ### Attack Path 1. An attacker-controlled workflow or caller obtains access to `record_screen()`. 2. The caller supplies a writable existing path or an FFmpeg-supported o ...[truncated 1123 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (30)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · __init__.py (reported line 755)May include surrounding context.

python
Activate a window by title substring using wmctrl.
        """
        try:
            env = os.environ.copy()
            if not env.get("DISPLAY"):
                detected = self._auto_detect_display()
                if detected:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents and demonstrates desktop automation features that imply shell execution, file access, and environment inspection, but it declares no explicit tool scope or permission boundaries. That mismatch increases the chance an agent can invoke powerful capabilities without clear user consent or policy enforcement, especially given functions like launching apps, recording screens, and writing files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The screenshot example explicitly disables approval mode and writes screen contents to a file without any privacy warning. Screenshots can capture passwords, messages, tokens, internal documents, or unrelated user data, so normalizing no-approval capture makes accidental sensitive-data collection more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The screen recording example records 30 seconds of desktop activity with approval disabled and no warning about capturing sensitive on-screen content. Recording is higher risk than a still screenshot because it can continuously collect credentials, chats, notifications, and workflow context over time.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The OCR example extracts text from whatever is visible on screen without warning that this may include secrets or personal data. OCR turns transient visual content into searchable text, which materially increases the risk of exposing passwords, tokens, emails, or confidential business information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The flow recording and replay example captures and replays user interactions without warning about the sensitivity of recorded actions. Such recordings can encode credentials, personal messages, destructive UI sequences, or privileged administrative actions that could later be replayed unintentionally or abusively.

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 · __init__.py (reported line 264)May include surrounding context.

python
import subprocess
        import re
        try:
            out = subprocess.check_output(['xrandr'], text=True)
            monitors = []
            for line in out.split('\n'):
                # Match: "HDMI-0 connected primary 1920x1080+1366+0"

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

OCR-based text extraction significantly increases the ability to harvest sensitive data from the screen, including emails, tokens, messages, and other visible secrets. Because this capability is not clearly disclosed in the skill description, consumers may grant the skill broader trust than intended.

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 · __init__.py (reported line 414)May include surrounding context.

python
import subprocess
        try:
            # Get window ID
            out = subprocess.check_output(['wmctrl', '-l'], text=True)
            for line in out.split('\n'):
                if title_substring.lower() in line.lower():
                    win_id = line.split()[0]

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 · __init__.py (reported line 428)May include surrounding context.

python
import subprocess
        try:
            # Get window ID
            out = subprocess.check_output(['wmctrl', '-l'], text=True)
            for line in out.split('\n'):
                if title_substring.lower() in line.lower():
                    win_id = line.split()[0]

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 · __init__.py (reported line 442)May include surrounding context.

python
import subprocess
        try:
            # Get window ID
            out = subprocess.check_output(['wmctrl', '-l'], text=True)
            for line in out.split('\n'):
                if title_substring.lower() in line.lower():
                    win_id = line.split()[0]

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 · __init__.py (reported line 418)May include surrounding context.

python
for line in out.split('\n'):
                if title_substring.lower() in line.lower():
                    win_id = line.split()[0]
                    subprocess.run(['wmctrl', '-ir', win_id, '-e', f'0,-1,-1,{width},{height}'])
                    return True
            return False
        except Exception as e:

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 · __init__.py (reported line 432)May include surrounding context.

python
for line in out.split('\n'):
                if title_substring.lower() in line.lower():
                    win_id = line.split()[0]
                    subprocess.run(['xdotool', 'windowminimize', win_id])
                    return True
            return False
        except Exception as e:

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 · __init__.py (reported line 446)May include surrounding context.

python
for line in out.split('\n'):
                if title_substring.lower() in line.lower():
                    win_id = line.split()[0]
                    subprocess.run(['wmctrl', '-ir', win_id, '-b', 'add,maximized_vert,maximized_horz'])
                    return True
            return False
        except Exception as e:

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 · __init__.py (reported line 471)May include surrounding context.

python
"""Detect current keyboard layout (returns: qwerty, qwertz, azerty, unknown)."""
        try:
            import subprocess
            out = subprocess.check_output(['setxkbmap', '-query'], text=True)
            layout = out.get('layout', '')
            if 'us' in layout:
                return 'qwerty'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The screenshot and screenshot_to methods can capture and persist screen contents without any per-action approval or user-facing disclosure. Because screenshots often contain secrets or personal data, saving them directly to attacker-chosen paths increases the risk of covert data collection and retention.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description frames the capability as mouse/keyboard/screenshot automation, but the code also records full-screen video sessions. That materially expands surveillance and data-capture scope, making it easier to collect sensitive on-screen information without users or integrators understanding the true capability surface.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

record_screen captures the full display to disk without any approval check, even though the class advertises approval mode as a safety feature. This enables silent collection of sensitive visual data, including messages, credentials, documents, and other user activity, and can create durable artifacts on disk for later exfiltration.

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 · __init__.py (reported line 708)May include surrounding context.

python
"-r", str(fps),
            output_path
        ]
        subprocess.run(cmd, check=True)
        return output_path

    def get_pixel_color(self, x: int, y: int) -> Tuple[int, int, int]:

Tainted flow: 'cmd' from os.environ.get (line 699, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · __init__.py (reported line 708)May include surrounding context.

python
"-r", str(fps),
            output_path
        ]
        subprocess.run(cmd, check=True)
        return output_path

    def get_pixel_color(self, x: int, y: int) -> Tuple[int, int, int]:

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 · __init__.py (reported line 734)May include surrounding context.

python
"""
        try:
            import subprocess
            out = subprocess.check_output(["wmctrl", "-l"], text=True)
            titles = []
            for line in out.splitlines():
                parts = line.split(None, 3)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · __init__.py (reported line 744)May include surrounding context.

python
titles.append(title)
            return titles
        except FileNotFoundError:
            logger.error("wmctrl not found. Install: sudo apt-get install wmctrl")
            return []
        except Exception as e:
            logger.error(f"Error getting windows: {e}")

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · __init__.py (reported line 763)May include surrounding context.

python
titles.append(title)
            return titles
        except FileNotFoundError:
            logger.error("wmctrl not found. Install: sudo apt-get install wmctrl")
            return []
        except Exception as e:
            logger.error(f"Error getting windows: {e}")

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · __init__.py (reported line 783)May include surrounding context.

python
titles.append(title)
            return titles
        except FileNotFoundError:
            logger.error("wmctrl not found. Install: sudo apt-get install wmctrl")
            return []
        except Exception as e:
            logger.error(f"Error getting windows: {e}")

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 · __init__.py (reported line 760)May include surrounding context.

python
detected = self._auto_detect_display()
                if detected:
                    env["DISPLAY"] = detected
            subprocess.check_call(["wmctrl", "-a", title_substring], env=env)
            return True
        except FileNotFoundError:
            logger.error("wmctrl not found. Install: sudo apt-get install wmctrl")

Static analysis

No suspicious patterns detected.