Back to skill

Security audit

printer-control

Security checks for vulnerabilities and agentic risk

Overview

The skill’s printer-control purpose is clear, but its PowerShell fallbacks unsafely turn printer names and file paths into executable commands.

Review before installing. Use only with trusted printer names and file paths, prefer pywin32, and avoid the PowerShell fallback until it is changed to pass printer names and paths as data rather than interpolating them into scripts. Be aware that printing may consume resources or expose content at the wrong physical printer, and setting the default printer persists after the command.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/print_file.py:106
Finding

PowerShell Command Injection in File Printing Fallback

Content
View full analysis

Vulnerability Details

File Location: scripts/print_file.py:106-148
Vulnerability Type: PowerShell command injection
Risk Level: High

Vulnerable Code

python
ps_script = f"""
$printer = Get-Printer -Name "{printer_name}"
$printJob = $printer | Start-PrintJob
# Note: PowerShell printing is limited, may not work for all file types
"""

result = subprocess.run(
    ['powershell', '-Command', ps_script],
    capture_output=True,
    text=True,
    timeout=30
)

The non-text-file branch contains a second vulnerable construction:

python
ps_script = f"""
$filePath = "{file_path}"
$printerName = "{printer_name}"

# Set as default printer temporarily
$printer = Get-Printer -Name $printerName -ErrorAction Stop
$oldDefault = (Get-Printer | Where-Object {{$_.Default -eq $true}}).Name

if ($oldDefault -ne $printerName) {{
    $printer | Set-Printer -Shared $printer.Shared
}}

# Print the file
Start-Process -FilePath $filePath -Verb Print -WindowStyle Hidden

# Restore default printer
if ($oldDefault) {{
    Get-Printer -Name $oldDefault | Set-Printer -Shared (Get-Printer -Name $oldDefault).Shared
}}
"""

result = subprocess.run(
    ['powershell', '-Command', ps_script],
    capture_output=True,
    text=True,
    timeout=30
)

Technical Analysis

The CLI-controlled printer_name and file_path values are inserted directly into double-quoted PowerShell expressions. PowerShell parses the resulting string as source code because it is passed to powershell -Command.

Using an argument list for subprocess.run prevents command-shell interpretation by Python, but it does not prevent PowerShell from evaluating syntax inside the supplied script. Double-quoted PowerShell strings support variable and subexpression expansion. Consequently, characters such as $() can turn data embedded in a quoted value into executable PowerShell expressions. A valid W ...[truncated 1211 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not interpolate CLI values into PowerShell source code.
  • Prefer pywin32 or another structured printing API that accepts printer names and file paths as data.
  • If PowerShell is unavoidable, pass values through environment variables, standard input, or a parameterized script file and retrieve them as literal data.
  • Use PowerShell's stop-parsing or Base64-encoded data only for transporting values, not as a substitute for validation.
  • Validate the printer against an enumerated exact-name allowlist.
  • Resolve and validate the file path before invocation, require a regular file, and enforce any intended directory or extension restrictions.
  • Add regression tests containing PowerShell metacharacters and subexpression syntax in all externally supplied values.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/print_text.py:88
Finding

PowerShell Command Injection Through Printer Name in Text Printing

Content
View full analysis

Vulnerability Details

File Location: scripts/print_text.py:88-114
Vulnerability Type: PowerShell command injection
Risk Level: High

Vulnerable Code

python
actual_name = find_printer_by_partial_name(printer_name)
if actual_name:
    printer_name = actual_name
    print(f"[INFO] Found printer: {printer_name}")

try:
    # Escape special characters for PowerShell
    escaped_text = text.replace("'", "''").replace('$', '`$').replace('"', '`"')

    ps_script = f"""
    $printer = Get-Printer -Name "{printer_name}" -ErrorAction Stop

    # Create a temporary text file
    $tempFile = [System.IO.Path]::GetTempFileName()
    "{escaped_text}" | Out-File -FilePath $tempFile -Encoding UTF8

    # Print the file using Notepad
    $notepad = Start-Process notepad.exe -ArgumentList "/p $tempFile" -PassThru -WindowStyle Hidden
    $notepad.WaitForExit(5000)

    # Clean up temp file after a short delay
    Start-Sleep -Seconds 2
    Remove-Item $tempFile -Force
    """

    result = subprocess.run(
        ['powershell', '-Command', ps_script],
        capture_output=True,
        text=True,
        timeout=30
    )

Technical Analysis

The function attempts to escape the text content but performs no corresponding encoding or escaping for printer_name. If partial-name lookup fails, the original CLI-supplied value remains unchanged. It is then embedded directly inside a double-quoted PowerShell expression and passed to powershell -Command.

A malicious printer argument can therefore alter the generated script or invoke PowerShell subexpressions. The initial Get-Printer command does not provide protection because expression evaluation occurs while PowerShell parses and evaluates the argument.

Attack Path

  1. An attacker supplies a crafted --printer value that does not resolve to a safe enumerated printer name.
  2. pywin32 is unavailable or its operation fails. ...[truncated 553 chars]
Remediation
View remediation

Remediation Suggestions

  • Require an exact printer match from a trusted enumeration result before reaching the fallback.
  • Never concatenate the printer name into executable PowerShell text.
  • Pass the printer name as an environment variable or parameter to a fixed script and treat it strictly as data.
  • Prefer a structured Windows printing API that directly accepts a printer handle.
  • Reject unmatched printer names instead of retaining and executing with the original input.
  • Add tests for quotes, dollar signs, subexpressions, backticks, newlines, and statement separators in printer arguments.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/set_default.py:27
Finding

PowerShell Command Injection in Default-Printer Configuration

Content
View full analysis

Vulnerability Details

File Location: scripts/set_default.py:27-42
Vulnerability Type: PowerShell command injection
Risk Level: High

Vulnerable Code

python
def set_default_powershell(printer_name):
    """Set default printer using PowerShell (fallback)."""
    import subprocess

    try:
        ps_script = f"""
        $printer = Get-Printer -Name "{printer_name}" -ErrorAction Stop
        $printer | Set-Printer -Default
        """

        result = subprocess.run(
            ['powershell', '-Command', ps_script],
            capture_output=True,
            text=True,
            timeout=10
        )

Technical Analysis

The required --printer CLI argument is passed to this function without validation against the installed printer list. The value is directly embedded into a double-quoted PowerShell command and executed through powershell -Command.

PowerShell evaluates interpolated expressions and control syntax in the generated script. This converts an ostensibly data-only printer name into an executable-code channel. The fallback runs whenever pywin32 is missing or SetDefaultPrinter fails.

Attack Path

  1. An attacker controls or influences the --printer argument.
  2. The pywin32 implementation is unavailable or returns an error.
  3. The fallback constructs a PowerShell script containing the raw printer argument.
  4. PowerShell evaluates attacker-supplied syntax.
  5. Commands execute using the security context of the skill process.

Impact Assessment

An attacker can execute arbitrary PowerShell commands with the current user's privileges. This permits access to the user's files and resources, process execution, and configuration changes that the current user is authorized to perform. The vulnerable code does not directly provide administrator privileges.

Remediation
View remediation

Remediation Suggestions

  • Enumerate installed printers and require an exact, unambiguous match before changing the default.
  • Replace dynamically generated PowerShell with a fixed, parameterized script.
  • Transport the selected printer name as data through an environment variable or another non-code channel.
  • Prefer win32print.SetDefaultPrinter and fail safely when that supported API is unavailable.
  • Do not invoke a fallback after arbitrary pywin32 errors without distinguishing unavailable dependencies from invalid input or access failures.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/printer_status.py:106
Finding

PowerShell Injection Through Crafted Installed Printer Names in Status Queries

Content
View full analysis

Vulnerability Details

File Location: scripts/printer_status.py:106-128
Vulnerability Type: PowerShell command injection from a system-controlled printer name
Risk Level: Medium

Vulnerable Code

python
def get_printer_status_powershell(printer_name):
    """Get printer status using PowerShell (fallback)."""
    import subprocess

    try:
        ps_script = f"""
        $printer = Get-Printer -Name "{printer_name}" -ErrorAction Stop
        [PSCustomObject]@{{
            Name = $printer.Name
            Type = $printer.Type
            PortName = $printer.PortName
            Shared = $printer.Shared
            Default = $printer.Default
            Status = if ($printer.WorkOffline) {{ "Offline" }} else {{ "Online" }}
        }} | ConvertTo-Json
        """

        result = subprocess.run(
            ['powershell', '-Command', ps_script],
            capture_output=True,
            text=True,
            timeout=10
        )

The --all path passes every enumerated printer name to the vulnerable function:

python
if args.all:
    for printer_name in printers:
        status = get_printer_status_pywin32(printer_name)
        if status is None:
            status = get_printer_status_powershell(printer_name)

Technical Analysis

Printer names are interpolated into executable PowerShell source without literal encoding. The single-printer path checks that the requested value is in the enumerated printer list, but this does not make the value safe for insertion into source code. The --all path automatically processes every enumerated printer.

Exploitation requires an attacker to create, rename, advertise, or otherwise cause a crafted printer name to appear in the victim's printer enumeration. This prerequisite reduces exploitability compared with the directly CLI-controlled injection points, but the resulting sink is still unsafe.

Attac

...[truncated 775 chars]

Remediation
View remediation

Remediation Suggestions

  • Treat operating-system object names as untrusted data even when obtained from local enumeration.
  • Do not interpolate enumerated printer names into PowerShell source.
  • Use a fixed script that reads the printer name from a data-only channel.
  • Prefer pywin32 printer-status APIs and report an unsupported-platform error when a safe fallback is unavailable.
  • Add tests using printer names containing PowerShell metacharacters and subexpression syntax.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/print_file.py:124
Finding

File Printing Fallback Does Not Honor the Selected Printer

Content
View full analysis

Vulnerability Details

File Location: scripts/print_file.py:124-153
Vulnerability Type: Incorrect print-destination handling and potential physical information disclosure
Risk Level: Medium

Vulnerable Code

python
# For PDF and other files, use Start-Process with -Verb Print
else:
    ps_script = f"""
    $filePath = "{file_path}"
    $printerName = "{printer_name}"

    # Set as default printer temporarily
    $printer = Get-Printer -Name $printerName -ErrorAction Stop
    $oldDefault = (Get-Printer | Where-Object {{$_.Default -eq $true}}).Name

    if ($oldDefault -ne $printerName) {{
        $printer | Set-Printer -Shared $printer.Shared
    }}

    # Print the file
    Start-Process -FilePath $filePath -Verb Print -WindowStyle Hidden

    # Restore default printer
    if ($oldDefault) {{
        Get-Printer -Name $oldDefault | Set-Printer -Shared (Get-Printer -Name $oldDefault).Shared
    }}
    """

    result = subprocess.run(
        ['powershell', '-Command', ps_script],
        capture_output=True,
        text=True,
        timeout=30
    )

    if result.returncode == 0:
        return True, f"Print job sent to {printer_name} (using default printer method)"

Technical Analysis

The code comments claim that it temporarily sets the selected printer as the default, but Set-Printer -Shared only modifies or reapplies the sharing property. It does not make the selected printer the default printer.

Start-Process -Verb Print delegates printing to the file type's registered application, which normally prints through that application's default behavior. Because the selected printer was not made the default and is not passed to the application, the document can be sent to the current default printer instead.

The function then reports success using the requested printer name without verifying the actual print destination.

Attack Path

  1. A user s ...[truncated 788 chars]
Remediation
View remediation

Remediation Suggestions

  • Use a printing API that explicitly binds the job to the selected printer.
  • Do not use Start-Process -Verb Print when a destination printer must be guaranteed.
  • Remove the ineffective Set-Printer -Shared operations.
  • If destination-specific printing is unavailable, stop with an error rather than silently printing through the default application.
  • Verify the submitted print job's destination before returning success.
  • Clearly distinguish job submission from confirmed printing in status messages.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/print_text.py:96
Finding

Text Printing Fallback Ignores the Selected Printer

Content
View full analysis

Vulnerability Details

File Location: scripts/print_text.py:96-121
Vulnerability Type: Incorrect print-destination handling and potential physical information disclosure
Risk Level: Medium

Vulnerable Code

python
ps_script = f"""
$printer = Get-Printer -Name "{printer_name}" -ErrorAction Stop

# Create a temporary text file
$tempFile = [System.IO.Path]::GetTempFileName()
"{escaped_text}" | Out-File -FilePath $tempFile -Encoding UTF8

# Print the file using Notepad
$notepad = Start-Process notepad.exe -ArgumentList "/p $tempFile" -PassThru -WindowStyle Hidden
$notepad.WaitForExit(5000)

# Clean up temp file after a short delay
Start-Sleep -Seconds 2
Remove-Item $tempFile -Force
"""

result = subprocess.run(
    ['powershell', '-Command', ps_script],
    capture_output=True,
    text=True,
    timeout=30
)

if result.returncode == 0:
    return True, f"Print job sent to {printer_name}"

Technical Analysis

The selected printer is retrieved with Get-Printer, but the resulting $printer object is never used when the print process is started. Notepad's /p option prints the supplied file using the default printer; it does not accept the selected $printer object in this invocation.

As a result, the script may send the text to the current default printer while reporting that it was sent to the requested printer. Waiting for Notepad to exit does not verify the actual destination or successful completion of the spooler job.

Attack Path

  1. A user requests that sensitive text be printed on a particular printer.
  2. pywin32 is unavailable or fails, activating the PowerShell fallback.
  3. The fallback confirms that the named printer exists but does not associate it with the Notepad process.
  4. Notepad prints the temporary file using the current default printer.
  5. The script returns a success message naming the requested printer rather than the actual destination. ...[truncated 289 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace Notepad /p with a printing API that explicitly receives the selected printer.
  • Use the validated printer handle or name when submitting the job.
  • Fail closed when targeted printing cannot be guaranteed.
  • Verify the spooler destination and job identifier before reporting success.
  • Ensure temporary print data is removed in a finally block after confirmed job submission, while allowing enough time for the printing process to consume it.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

A language-specific documentation requirement can violate language/locale policy when it forces one language without user opt-in or justification. This file presents all operational instructions in Chinese and does not indicate any alternative language option or region-specific scope.

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

python
def list_printers_powershell():
    """List printers using PowerShell (fallback)."""
    try:
        result = subprocess.run(
            ['powershell', '-Command', 
             'Get-Printer | Select-Object Name,Type,Shared,PortName | ConvertTo-Json'],
            capture_output=True,

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The module documentation says the script will print a text file to a specified printer, implying a direct, limited print action. However, the PowerShell fallback modifies printer state via Set-Printer and uses a 'default printer method', which is broader behavior than the stated intent and not simply a direct send to the named printer.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This call executes a PowerShell script built with direct interpolation of user-controlled printer_name into a double-quoted PowerShell string. An attacker who can supply a crafted printer name containing PowerShell metacharacters or quote-breaking content could inject arbitrary commands under the privileges of the script.

Content

Scanner excerpt · scripts/print_file.py (reported line 112)May include surrounding context.

python
# Note: PowerShell printing is limited, may not work for all file types
            """
            
            result = subprocess.run(
                ['powershell', '-Command', ps_script],
                capture_output=True,
                text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

This subprocess call runs a dynamically constructed PowerShell script containing both file_path and printer_name inside interpolated double-quoted strings. Because both values are user-controlled CLI inputs, this creates a command injection path that could execute arbitrary PowerShell commands, and the fallback logic also changes printer state in a way that broadens side effects beyond simple printing.

Content

Scanner excerpt · scripts/print_file.py (reported line 147)May include surrounding context.

python
}}
            """
            
            result = subprocess.run(
                ['powershell', '-Command', ps_script],
                capture_output=True,
                text=True,

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

python
# Get all printers
    try:
        result = subprocess.run(
            ['powershell', '-Command', 
             'Get-Printer | Select-Object Name,PortName | ConvertTo-Json'],
            capture_output=True,

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

python
# Get all printers
    try:
        result = subprocess.run(
            ['powershell', '-Command', 
             'Get-Printer | Select-Object Name,PortName | ConvertTo-Json'],
            capture_output=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
91% confidence
Finding

This code builds a PowerShell script by interpolating user-controlled printer_name and text into the script body, then executes it with powershell -Command. Although some escaping is attempted for text, printer_name is inserted directly into a quoted PowerShell string, enabling command/script injection if an attacker can control the printer argument; the fallback path also increases exposure because it is automatically used when pywin32 is unavailable or fails.

Content

Scanner excerpt · scripts/print_text.py (reported line 113)May include surrounding context.

python
Remove-Item $tempFile -Force
        """
        
        result = subprocess.run(
            ['powershell', '-Command', ps_script],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The PowerShell command string is built with an f-string that directly embeds the user-controlled printer_name inside quoted PowerShell code. An attacker can supply a printer name containing quotes or PowerShell metacharacters to break out of the string and execute arbitrary commands when subprocess.run invokes powershell, leading to command injection.

Content

Scanner excerpt · scripts/printer_status.py (reported line 123)May include surrounding context.

python
}} | ConvertTo-Json
        """
        
        result = subprocess.run(
            ['powershell', '-Command', ps_script],
            capture_output=True,
            text=True,

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

python
printers = [p[2] for p in printer_list]
    except:
        import subprocess
        result = subprocess.run(
            ['powershell', '-Command', 'Get-Printer | Select-Object -ExpandProperty Name'],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The PowerShell fallback builds a script by interpolating untrusted user input directly into a PowerShell command string and then executes it. A printer name containing quotes or PowerShell metacharacters can break out of the intended string context and inject arbitrary PowerShell commands, leading to command execution under the user's privileges.

Content

Scanner excerpt · scripts/set_default.py (reported line 37)May include surrounding context.

python
$printer | Set-Printer -Default
        """
        
        result = subprocess.run(
            ['powershell', '-Command', ps_script],
            capture_output=True,
            text=True,

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

python
try:
        import subprocess
        result = subprocess.run(
            ['powershell', '-Command', '(Get-Printer | Where-Object {$_.Default -eq $true}).Name'],
            capture_output=True,
            text=True,

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This markdown file documents operational steps for printing test text and files, which can affect user resources and data output. The instructions do not include any user-facing caution about selecting the correct printer, possible physical printing, or PDF/output-file creation when using a virtual printer.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring narrows the function's scope to 'PDF/text', but the implementation sends all other file types through the generic non-text branch. That is an active mismatch between documented intent and actual behavior, because formats beyond PDF are included in practice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.