Back to skill

Security audit

Ssh Tool

Security checks for vulnerabilities and agentic risk

Overview

The skill is a plausible SSH wrapper, but its bundled script can turn a host value into local SSH option execution and the skill does not clearly scope that authority.

Review this skill before installing. It should reject leading-dash hosts, validate destinations, and expose only an explicit allowlist of needed SSH options before being trusted for agent-driven use, especially where hostnames or commands may come from untrusted content.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ssh.py:4
Finding

SSH Option Injection Through Unvalidated Host Argument

Content
View full analysis

Vulnerability Details

File Location: scripts/ssh.py:4-8
Vulnerability Type: SSH option injection leading to local command execution
Risk Level: High

python
parser = argparse.ArgumentParser()
parser.add_argument('host')
parser.add_argument('cmd', nargs='*')
args = parser.parse_args()
cmd = ['ssh', args.host] + (args.cmd or [])

Technical Analysis

The positional host argument is passed directly to the OpenSSH client without validation or an effective option boundary. If this value begins with -, OpenSSH can interpret it as an option rather than as a destination hostname.

Although argparse normally treats leading-dash values as options, an attacker can place its -- end-of-options marker before the crafted positional argument. The resulting value is then copied unchanged into the SSH command. OpenSSH options such as -oProxyCommand=... can specify a local process that SSH executes while establishing a connection.

Because subprocess.run() receives an argument list rather than a shell command, conventional shell metacharacter injection is not the issue. The vulnerability instead arises from argument injection into the invoked SSH program and the dangerous semantics of accepted OpenSSH options.

Attack Path

  1. An attacker gains control over, or influences, arguments supplied to the wrapper.
  2. The attacker uses the wrapper's -- separator to submit a leading-dash value as the positional host.
  3. The crafted host contains an OpenSSH option such as -oProxyCommand=....
  4. A subsequent positional value can act as the actual SSH destination.
  5. The wrapper constructs an argument vector equivalent to:
    text
    ssh -oProxyCommand=<attacker-controlled command> <destination>
    
  6. OpenSSH interprets the injected value as configuration and starts the attacker-selected proxy command locally.

This path is exploitable when an untrusted user, upstream agent, o ...[truncated 672 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject host values beginning with - before invoking SSH:

    python
    if args.host.startswith('-'):
        parser.error('host must not begin with "-"')
    
  2. Strictly validate the destination against the hostname formats the tool intends to support, such as a DNS name, IP address, or controlled user@host form. Avoid accepting arbitrary SSH destination syntax unless explicitly required.

  3. Insert an end-of-options delimiter before the host if the supported OpenSSH implementation handles it reliably:

    python
    cmd = ['ssh', '--', args.host] + args.cmd
    

    Host validation should still be retained as defense in depth and for portability.

  4. If SSH options are required, define them as explicit wrapper arguments and allowlist only necessary options. Do not forward unrestricted OpenSSH configuration options from untrusted input.

  5. Add regression tests covering leading-dash destinations, including -oProxyCommand, -F, -S, and similar configuration-bearing options.

  6. Run the wrapper with the least privileges required and prevent untrusted callers from controlling its complete argument list.

Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises shell-capable behavior via command-line usage and remote command execution, but the manifest does not declare any explicit tool scope such as 'permissions' or 'allowed-tools'. This creates an authorization and review gap: consumers and enforcement layers may not be able to clearly constrain or understand that the skill can invoke shell-like operations against remote hosts.

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

python
parser.add_argument('cmd', nargs='*')
args = parser.parse_args()
cmd = ['ssh', args.host] + (args.cmd or [])
subprocess.run(cmd)