Back to skill

Security audit

Docker Container Rerun

Security checks for vulnerabilities and agentic risk

Overview

This Docker update skill is purpose-aligned but needs Review because its helper script can execute a user-provided recreate command through Bash on the host.

Review before installing. Use only with recreate commands you wrote and understand, run without --apply first, avoid untrusted or copied shell text, and inspect for shell separators, command substitution, dangerous mounts, Docker socket access, --privileged, and --network host. Prefer pinned image tags or digests for critical services, and be aware that --apply can delete the old container before recreation succeeds.

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/update_docker_run_container.py:109
Finding

Arbitrary Host Command Execution Through an Unvalidated Recreate Command

Content
View full analysis

Vulnerability Details

File Location: scripts/update_docker_run_container.py, lines 35–38 and 109–112
Vulnerability Type: OS command injection caused by unsafe shell execution
Risk Level: High

Vulnerable Code

python
def validate_recreate_command(recreate_command: str) -> None:
    stripped = recreate_command.strip()
    if not stripped.startswith("docker run"):
        raise ValueError("recreate_command must start with 'docker run'")
python
def recreate(recreate_command: str) -> None:
    proc = subprocess.run(recreate_command, shell=True, executable="/bin/bash", text=True)
    if proc.returncode != 0:
        raise CommandError("recreate_command execution failed")

The vulnerable function is reached in apply mode at lines 154–157:

python
if needs_update and args.apply:
    stop_and_remove(args.container_name)
    recreate(args.recreate_command)
    recreated = True

Technical Analysis

The script accepts recreate_command from a command-line argument and eventually passes the complete value to Bash with shell=True. The only direct validation is a textual check that the stripped value starts with docker run.

This prefix check does not establish that the input contains only one Docker invocation. Shell metacharacters and constructs—including command separators, pipelines, redirections, command substitutions, and additional commands—remain available to the caller. Although extract_image() uses shlex.split() to identify an image, the resulting tokens are not used for execution and therefore do not mitigate injection.

A crafted value can start with a syntactically valid Docker command, pass validation and image extraction, and then append another host command. Bash interprets that additional content when recreate() is called.

The workflow amplifies the operational risk because it stops and removes the existing container before executing the untrusted shell string. If the Docker invocation or injected su ...[truncated 1617 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not execute the recreate command through a shell. Parse the command into an argument vector and invoke Docker directly:

    python
    tokens = shlex.split(recreate_command, posix=True)
    subprocess.run(tokens, shell=False, check=True, text=True)
    
  2. Validate the complete token vector. Require the first two tokens to be exactly docker and run, confirm that an image exists, and reject unsupported or ambiguous syntax. Do not rely on a string-prefix check.

  3. Reject shell-specific constructs. If the interface must continue accepting a command string, reject separators, pipelines, redirections, substitutions, and other syntax that requires shell interpretation. Prefer accepting structured arguments rather than attempting to sanitize shell text.

  4. Use one parser for validation and execution. Execute the exact token array that was validated and used to extract the image. Do not validate one interpretation and later execute the original string under Bash.

  5. Verify container identity. Parse the --name option and require it to match --container-name, preventing replacement commands from targeting an unintended logical container.

  6. Reduce service-loss risk. Fully validate the replacement invocation before stopping the existing container. Consider creating and verifying a replacement under a temporary name before removing the old container, where Docker naming and resource constraints permit it.

  7. Implement failure recovery. If recreation fails after removal, provide a tested rollback mechanism or preserve sufficient trusted state to restore the prior container safely.

  8. Add adversarial tests. Cover command separators, command substitutions, pipelines, redirections, multiline input, malformed quoting, unsupported Docker options, mismatched container names, and failed recreation after removal.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (18)

Privileged Container / Container Escape

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The skill includes and normalizes an example recreate_command using --network host, and the workflow says to preserve the recreate command exactly rather than reject dangerous flags. Host networking substantially weakens container isolation, can expose host services and broaden lateral movement, and in this skill's context it may be automatically re-applied during recreation of an existing container.

Content

Scanner excerpt · SKILL.md (reported line 142)May include surrounding context.

  • container_name: my-container
  • recreate_command:
    bash
    docker run -d --network host --name my-container --restart unless-stopped -v example_data:/data -v example_certs:/etc/ssl/certs -e DB_HOST=<db_host> -e DB_PORT=<db_port> -e DB_NAME=<db_name> -e DB_USER=<db_user> -e DB_PASSWORD=<db_password> --health-cmd="/bin/check-health" --health-interval=600s --health-retries=5 --health-timeout=3s example/image:latest
    

Expected behavior:

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
100% confidence
Finding

The recreate_command parameter is attacker-controlled input that is executed by Bash with shell=True after only a weak prefix check. An adversary can supply input like 'docker run ...; curl ... | bash' or use command substitution inside arguments, leading to arbitrary code execution on the host with the privileges of the agent process.

Content

Scanner excerpt · scripts/update_docker_run_container.py (reported line 107)May include surrounding context.

python
def recreate(recreate_command: str) -> None:
    proc = subprocess.run(recreate_command, shell=True, executable="/bin/bash", text=True)
    if proc.returncode != 0:
        raise CommandError("recreate_command execution failed")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill clearly instructs the agent to execute shell commands (docker inspect, docker pull, docker stop, docker rm, and a bundled Python script) but does not declare any tool scope or execution permissions. That mismatch is dangerous because it hides operational capability from policy/review layers and can enable unintended shell execution without explicit least-privilege constraints.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

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

python
def run(cmd, check=True, capture=True):
    proc = subprocess.run(
        cmd,
        text=True,
        capture_output=capture,

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

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

python
def pull_image(image: str) -> None:
    proc = subprocess.run(["docker", "pull", image], text=True)
    if proc.returncode != 0:
        raise CommandError(f"docker pull failed for image: {image}")

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code performs shell-based execution of a high-impact command without clear disclosure, and because the command is user-supplied it compounds the risk of arbitrary host command execution. In the context of a container-management skill, users may assume only Docker actions occur, making the hidden shell semantics especially dangerous.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

This executes a user-provided string via /bin/bash with shell=True, which allows arbitrary shell metacharacters, command substitution, chaining, redirection, and environment abuse. The prior validation only checks that the string starts with 'docker run', so an attacker can append additional commands and obtain arbitrary code execution on the host running the skill.

Content

Scanner excerpt · scripts/update_docker_run_container.py (reported line 107)May include surrounding context.

python
def recreate(recreate_command: str) -> None:
    proc = subprocess.run(recreate_command, shell=True, executable="/bin/bash", text=True)
    if proc.returncode != 0:
        raise CommandError("recreate_command execution failed")

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description implies a safe check-before-change workflow, but the implementation always performs docker pull even without --apply. Pulling mutates local state, consumes network resources, may update cached images unexpectedly, and can trigger authentication or audit side effects, so the tool does more than a passive check.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

When --apply is set, the script stops, removes, and recreates a container, which is a destructive operational change. Although the flag name hints at action, the code provides no confirmation prompt, no user-facing warning before execution, and no inline comment or docstring disclosing the impact of these operations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The function collects docker inspect output and the last 100 lines of container logs, then returns them in the result even though the skill's stated purpose is image comparison and optional recreation. Container logs and runtime metadata commonly contain secrets, tokens, internal URLs, and sensitive operational details, so this broadens data exposure beyond the intended scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.