Back to skill

Security audit

Remote Install

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to automate Windows software installation, but it can expose remote-access credentials and run installers with broad, under-controlled authority.

Review carefully before installing. This should only be used in a controlled Windows test environment until it stops logging passwords, separates local and remote execution clearly, requires explicit approval for each installer, verifies package signatures or hashes, and pins dependencies.

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
scripts/remote_installer.py:82
Finding

RustDesk Credentials Are Exposed Through Logs and Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/remote_installer.py:82-84 and scripts/remote_installer.py:732-735
Vulnerability Type: Plaintext credential exposure
Risk Level: High

Vulnerable Code

python
def connect(self, remote_id, password, timeout=60):
    """Connect to a remote computer."""
    logging.info(f"Starting RustDesk connection: ID={remote_id}, password={password}")
python
parser.add_argument('--remote-id', help='RustDesk remote ID')
parser.add_argument('--password', help='RustDesk verification password')

The displayed English text is a direct translation of the original log and help strings; the executable behavior is unchanged.

Technical Analysis

The RustDesk password is interpolated directly into an INFO-level log message. Logging is configured to write to scripts/installer.log, meaning the plaintext credential can remain on disk after the installation session ends.

The password is also accepted as a command-line argument. On systems where process arguments are visible to other users or monitoring tools, the value may be exposed through process listings, diagnostic collectors, shell history, job definitions, or endpoint monitoring records.

RustDesk passwords are authentication credentials. They must be handled as secrets and must not be included in ordinary application logs or command-line arguments.

Attack Path

  1. An operator invokes the script with --password and a RustDesk credential.
  2. The credential becomes visible in the process command line.
  3. The connect method writes the remote ID and plaintext password to scripts/installer.log.
  4. A local user, log collector, support tool, or compromised process reads the log or captured process arguments.
  5. The attacker reuses the recovered credential to attempt access to the associated RustDesk endpoint.

Impact Assessment

Successful exploitation discloses remote-access credential ...[truncated 398 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the password from all log messages. Log only a redacted remote ID where operationally necessary.
  • Replace the --password argument with getpass.getpass(), protected standard input, or an operating-system secret provider.
  • Add a logging filter that redacts credentials, tokens, and other sensitive fields.
  • Restrict access to installer.log and define a short retention policy.
  • Rotate any RustDesk credentials that may already have been written to logs.
  • Add automated tests that fail if sensitive parameter names or values appear in generated logs.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/remote_installer.py:642
Finding

Remote Installation Workflow Executes Packages on the Local Host

Content
View full analysis

Vulnerability Details

File Location: scripts/remote_installer.py:642-659
Vulnerability Type: Incorrect trust boundary and execution target
Risk Level: High

Vulnerable Code

python
# Find or validate the installer package
if installer_path and os.path.exists(installer_path):
    logging.info(f"Using specified installer package: {installer_path}")
else:
    # Search on the remote computer
    installers = self.find_installers()
    if not installers:
        result["message"] = "No installer package found"
        return result
    installer_path = installers[0]
    logging.info(f"Found installer package: {installer_path}")

# Perform installation
if not software_name:
    software_name = self.detect_software_type(installer_path)

arch = self.get_recommended_architecture(software_name)
logging.info(f"Recommended architecture: {arch}-bit")

install_result = self.install_package(installer_path, software_name)

The displayed comments and strings are direct English translations of the original source. The control flow and executable statements are unchanged.

Technical Analysis

Establishing a RustDesk GUI connection does not change the filesystem or process-execution context of the Python process. Nevertheless, the remote workflow calls self.find_installers(), which scans directories derived from the local USERPROFILE, and then invokes self.install_package(), which uses local subprocess calls.

There is no code that transfers the installer to the remote endpoint, invokes a process through a remote execution API, or verifies that execution is occurring on the intended remote host. Therefore, the workflow described as remote installation can execute packages on the operator or Agent host.

This violates the expected host trust boundary and can cause privileged changes to the wrong system.

Attack Path

  1. An operator requests installation on a remote computer and su ...[truncated 992 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove remote mode unless a genuine, authenticated remote execution mechanism is implemented.
  • Use a target-bound deployment channel such as a managed endpoint agent, WinRM with appropriate controls, or an approved software deployment platform.
  • Explicitly identify and display the execution host before launching a package.
  • Verify the remote host identity and require confirmation when the current execution host does not match the selected target.
  • Keep local and remote installation implementations separate so local subprocess APIs cannot be called from the remote workflow.
  • Add integration tests that verify the process is created on the selected remote endpoint and never on the controller host.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/remote_installer.py:335
Finding

Recursively Discovered Installers Are Executed Without Authenticity Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/remote_installer.py:335-376 and scripts/remote_installer.py:691-700
Vulnerability Type: Untrusted executable discovery and execution
Risk Level: High

Vulnerable Code

python
extensions = self.config.get(
    'software_types', {}
).get(
    'installer_extensions',
    ['.exe', '.msi', '.zip', '.rar']
)
min_size = self.config.get('min_file_size_mb', 1) * 1024 * 1024

for search_path in search_paths:
    if not os.path.exists(search_path):
        continue

    logging.info(f"Searching directory: {search_path}")

    for root, dirs, files in os.walk(search_path):
        if 'extracted' in root.lower():
            continue

        for file in files:
            ext = os.path.splitext(file)[1].lower()
            if ext not in extensions:
                continue

            file_path = os.path.join(root, file)
            try:
                if os.path.getsize(file_path) < min_size:
                    continue
            except:
                continue

            if keywords:
                if not any(kw.lower() in file.lower() for kw in keywords):
                    continue

            logging.info(f"Found installer package: {file_path}")
            installers.append(file_path)
python
results = []
for installer in installers:
    software_name = self.detect_software_type(installer)
    arch = self.get_recommended_architecture(software_name)
    logging.info(f"Recommended architecture: {arch}-bit")

    result = self.install_package(installer, software_name)
    result['recommended_arch'] = arch
    results.append(result)

The displayed log strings are direct English translations of the original source. The executable logic is unchanged.

Technical Analysis

The Skill recursively scans broad user-controlled directories and treats filename extension and minimum size as ...[truncated 1647 chars]

Remediation
View remediation

Remediation Suggestions

  • Require explicit confirmation for each exact package path before execution.
  • Validate Authenticode signatures and compare the signer against an approved publisher allowlist.
  • Require expected SHA-256 hashes for managed installation packages.
  • Restrict discovery to a dedicated, access-controlled staging directory rather than recursively scanning user folders.
  • Reject unsigned packages unless an authorized exception is recorded.
  • Display package path, hash, signer, version, and intended target host before installation.
  • Avoid automatically installing every package returned by discovery.
  • Record validation results in an audit log without recording secrets.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/remote_installer.py:487
Finding

Installer Commands Are Constructed as Shell Strings

Content
View full analysis

Vulnerability Details

File Location: scripts/remote_installer.py:487-503 and scripts/remote_installer.py:549-555
Vulnerability Type: Unsafe shell command construction
Risk Level: Medium

Vulnerable Code

python
def install_msi(self, installer_path):
    """Install an MSI package."""
    cmd = f'msiexec /i "{installer_path}" /quiet /norestart'
    return self.run_command(cmd, "MSI")

def install_exe(self, installer_path):
    """Install an EXE package."""
    silent_params = ["/S", "/VERYSILENT", "/SILENT", "/quiet", "/q"]

    for param in silent_params:
        cmd = f'"{installer_path}" {param}'
        result = self.run_command(cmd, "EXE", timeout=60)
        if result.get('success'):
            return result
python
def run_command(self, cmd, pkg_type, timeout=None):
    """Run a command."""
    timeout = timeout or self.config.get(
        'installation', {}
    ).get('timeout_seconds', 300)

    try:
        logging.info(f"Executing command: {cmd}")
        result = subprocess.run(
            cmd,
            shell=True,
            timeout=timeout,
            capture_output=True,
            text=True
        )

The displayed comments and log strings are direct English translations of the original source. The executable statements are unchanged.

Technical Analysis

Installer paths are interpolated into command strings and passed to subprocess.run() with shell=True. This delegates parsing and executable resolution to the Windows command processor even though no shell functionality is required.

Quoting the current path value reduces some immediate metacharacter interpretation, and Windows filesystem paths cannot normally contain a double-quote character. Therefore, the observed code does not establish a universal filename-only injection primitive. However, the implementation remains unsafe because it depends on shell quoting rules, a ...[truncated 1555 chars]

Remediation
View remediation

Remediation Suggestions

  • Set shell=False and pass executable arguments as a list.
  • Use an explicit trusted path for msiexec.exe.
  • Validate that the selected package resolves to a regular file in an approved directory.
  • Do not create commands by concatenating user-controlled or filesystem-derived values.
  • Log structured arguments with sensitive values redacted.

Example:

python
subprocess.run(
    [
        trusted_msiexec_path,
        "/i",
        installer_path,
        "/quiet",
        "/norestart"
    ],
    shell=False,
    timeout=timeout,
    capture_output=True,
    text=True,
    check=False
)

For EXE packages:

python
subprocess.run(
    [installer_path, param],
    shell=False,
    timeout=timeout,
    capture_output=True,
    text=True,
    check=False
)

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Third-Party Dependencies Are Mutable and Installed Without Integrity Pinning

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-4 and SKILL.md:96
Vulnerability Type: Unpinned dependency supply-chain exposure
Risk Level: Medium

Vulnerable Code

text
pyautogui>=0.9.53
pygetwindow>=0.0.9
pywinauto>=0.6.8
Pillow>=9.0.0

The installation documentation also instructs users to install mutable package names directly:

bash
pip install pyautogui pywinauto Pillow

Technical Analysis

Every requirement uses an open-ended lower bound, allowing future package releases to be selected without review. No lock file or cryptographic hashes are supplied. Consequently, two installations performed at different times may resolve to different code.

The documented installation command is less complete than requirements.txt because it omits the directly imported pygetwindow dependency. It also installs the latest matching releases without integrity verification.

This does not prove that any currently named dependency is malicious. The issue is that dependency versions and artifacts are mutable and are accepted without a reviewed lock or hash, exposing installation to compromised releases, unsafe upstream changes, or unapproved package-index substitution.

Attack Path

  1. A dependency account, release process, distribution artifact, or configured package index is compromised.
  2. A malicious or otherwise unsafe version is published under an allowed package name and version.
  3. A user follows the documentation or installs from requirements.txt.
  4. The resolver selects the new version because the requirements contain only lower bounds.
  5. Package installation or subsequent import executes code from the unreviewed artifact under the installing user's privileges.

Impact Assessment

A compromised dependency can execute during installation or when imported by the script. The resulting privileges are those of the Python or package installation p ...[truncated 217 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin every direct and transitive dependency to a reviewed exact version.
  • Generate and commit a lock file for the supported Python environment.
  • Require hashes for downloaded artifacts, for example with pip --require-hashes.
  • Include pygetwindow in the documented installation procedure or direct users exclusively to the locked requirements file.
  • Install packages only from an approved index over authenticated TLS.
  • Perform dependency vulnerability and provenance scanning before releases.
  • Use a controlled update process that reviews and tests each dependency version change.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
100% confidence
Finding

The script logs the remote access ID and password in plaintext during connection attempts, directly exposing credentials in log files and console output. Anyone with access to logs can reuse those secrets to establish unauthorized remote sessions or move laterally.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The tool performs unattended software installation, GUI automation, and automatic button-clicking across installer dialogs without any explicit user confirmation, trust validation, or package provenance checks. In this context, that makes it easy to silently install unwanted or malicious software, especially since packages are auto-discovered in common user directories and may be run remotely.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is a true tool-parameter abuse issue because the script feeds a composed command string into subprocess.run with shell=True. In a skill designed to search for installers, execute them automatically, and even operate over remote access, any attacker influence over filenames, paths, or config can transform this into arbitrary command execution.

Content

Scanner excerpt · scripts/remote_installer.py (reported line 555)May include surrounding context.

python
try:
            logging.info(f"执行命令:{cmd}")
            result = subprocess.run(cmd, shell=True, timeout=timeout, capture_output=True, text=True)
            
            if result.returncode == 0:
                logging.info(f"{pkg_type}包安装成功")

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Most of the user-facing documentation, usage examples, workflow descriptions, and safety notes are written in Chinese, while the file does not state that the skill is region-specific or offer a language/locale opt-in. Under the policy, forcing a specific language without user choice can be 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
82% confidence
Finding

The module description and user-facing messages are presented in Chinese without indicating that language is configurable or optional. This can violate language/locale policy when a skill forces a specific language without user opt-in.

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/remote_installer.py (reported line 69)May include surrounding context.

python
for path in rustdesk_paths:
            if os.path.exists(path):
                logging.info(f"启动 RustDesk: {path}")
                self.process = subprocess.Popen(path)
                time.sleep(3)
                return True

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
76% confidence
Finding

Launching 'rustdesk' by bare executable name relies on PATH resolution, which can execute an attacker-controlled binary if the environment or search path is compromised. In an automation tool intended to perform remote access and installation, invoking the wrong binary could hand control to malicious software.

Content

Scanner excerpt · scripts/remote_installer.py (reported line 75)May include surrounding context.

python
logging.warning("未找到 RustDesk,尝试搜索...")
        try:
            self.process = subprocess.Popen(['rustdesk'])
            time.sleep(3)
            return True
        except:

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/remote_installer.py (reported line 511)May include surrounding context.

python
logging.info("静默安装失败,尝试 GUI 自动化...")
        try:
            subprocess.Popen(f'"{installer_path}"')
            time.sleep(3)
            self.handle_installation_gui()
            return {"success": True, "message": "EXE 包通过 GUI 自动化安装"}

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · scripts/remote_installer.py (reported line 549)May include surrounding context.

python
except Exception as e:
            return {"success": False, "message": f"解压失败:{e}"}
    
    def run_command(self, cmd, pkg_type, timeout=None):
        """运行命令"""
        timeout = timeout or self.config.get('installation', {}).get('timeout_seconds', 300)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The script constructs command strings from installer_path and executes them with shell=True, creating a command injection surface if the path or related input is attacker-controlled. Because the tool searches user-writable directories and can run remotely, a crafted filename or configuration could result in arbitrary command execution under the script's privileges.

Content

Scanner excerpt · scripts/remote_installer.py (reported line 555)May include surrounding context.

python
try:
            logging.info(f"执行命令:{cmd}")
            result = subprocess.run(cmd, shell=True, timeout=timeout, capture_output=True, text=True)
            
            if result.returncode == 0:
                logging.info(f"{pkg_type}包安装成功")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This config embeds specific language variants for UI button detection, including Chinese and English strings, but provides no natural-language indication of locale selection, user opt-in, or region-specific justification. Because the policy asks to flag language/locale constraints that are imposed without user choice, this may represent an undocumented locale assumption.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower bound only, which allows installation of any newer version and makes builds non-reproducible. This increases supply-chain risk because a vulnerable or malicious upstream release could be pulled in without review.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
pyautogui>=0.9.53
pygetwindow>=0.0.9
pywinauto>=0.6.8
Pillow>=9.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is unpinned and can resolve to different versions over time, reducing reproducibility and weakening supply-chain control. While not an exploit by itself, it creates exposure to unexpected vulnerable or compromised releases.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
pyautogui>=0.9.53
pygetwindow>=0.0.9
pywinauto>=0.6.8
Pillow>=9.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using only a minimum version for pywinauto permits unreviewed newer versions to be installed, which can introduce security regressions or malicious code through the package supply chain. This is especially relevant for automation libraries that may operate with broad desktop interaction capabilities.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
pyautogui>=0.9.53
pygetwindow>=0.0.9
pywinauto>=0.6.8
Pillow>=9.0.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

Pillow is unpinned, so the environment may install a version with known vulnerabilities or future unreviewed changes. Because Pillow has a history of security advisories and image parsing often handles attacker-controlled input, version ambiguity materially increases risk.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
pyautogui>=0.9.53
pygetwindow>=0.0.9
pywinauto>=0.6.8
Pillow>=9.0.0

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The manifest does not pin Pillow, and Pillow has multiple published advisories, so it is impossible to determine whether deployments will receive a safe version. If this skill processes untrusted images, affected Pillow versions could expose the system to denial of service or potentially code execution depending on the specific CVE.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/remote_installer.py (reported line 259)May include surrounding context.

python
def setup_logging(self):
        """设置日志"""
        log_level = getattr(logging, self.config.get('installation', {}).get('log_level', 'INFO'))
        script_dir = os.path.dirname(os.path.abspath(__file__))
        log_path = os.path.join(script_dir, 'installer.log')

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The method docstring at L682 explicitly describes this path as a local installation flow without remote behavior. However, the returned message at L724 states "远程安装流程完成" (remote installation flow completed), which directly contradicts the method's documented intent and can mislead operators or downstream systems about what actually occurred.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.