Back to skill

Security audit

Container Update Advisor

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says: checks running Docker containers for updates and reports them, with expected but limited exposure of container metadata and external release-note content.

Install only if you are comfortable letting the skill inspect your running Docker containers and contact Docker Hub and GitHub. Avoid setting GITHUB_TOKEN unless needed, review generated Markdown reports cautiously because changelog text comes from external repositories, and add cron scheduling only when you intentionally want recurring reports saved to disk.

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

Warning
Location
scripts/format_report.py:81
Finding
Unsanitized Remote Release Notes Embedded in Markdown Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/format_report.py`, lines 81–99 and 145–153 **Vulnerability Type**: Untrusted Markdown content injection **Risk Level**: Medium ### Vulnerable Code ```python if status == "found": releases = changelog.get("releases", []) if not releases: return "_No release notes found._" lines = [] for r in releases[:3]: tag = r.get("tag", "?") name = r.get("name", tag) body = r.get("body", "").strip() # Extract first meaningful paragraph if body: # Remove markdown headers, HTML tags body = re.sub(r'<[^>]+>', '', body) # Get first non-empty lines up to 400 chars paras = [p.strip() for p in body.split("\n") if p.strip()] snippet = " ".join(paras)[:400] if len(" ".join(paras)) > 400: snippet += "…" ``` ```python if source_url or gh_repo: url = source_url or f"https://github.com/{gh_repo}" lines.append(f"- **Source:** <{url}>") lines.append("") lines.append("**Changelog:**") lines.append(changelog_summary) return "\n".join(lines) ``` ### Technical Analysis Release-note bodies retrieved from GitHub are controlled by the referenced repository and must therefore be treated as untrusted remote input. The formatter removes HTML tags, but it does not escape or remove Markdown constructs such as: - Remote images: `![text](https://attacker.example/track)` - Deceptive hyperlinks: `[Security update](https://attacker.example/phish)` - Headings, block quotes, and other formatting capable of visually altering the report - Control characters or crafted text intended to obscure the report's trusted risk labels The resulting content is inserted directly into the generated Markdown report. HTML removal alone is insufficient because Markdown renderers can turn the remaining syntax into active external resources and misleading interactive content. This issue does not p ...[truncated 1804 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat all GitHub release metadata—including body, title, and tag—as untrusted input. 2. Convert release notes to escaped plain text before placing them in Markdown. At minimum, escape Markdown metacharacters such as backslashes, backticks, asterisks, underscores, braces, brackets, parentheses, angle brackets, hash signs, plus signs, minus signs, periods, exclamation marks, and pipes. 3. Explicitly remove Markdown image and link syntax rather than relying only on HTML-tag removal. 4. Strip control characters and normalize line breaks before truncation. 5. Place remote text in a clearly labeled, fenced plain-text block if compatible with the reporting format. Escape embedded backtick sequences before doing so. 6. Consider omitting release bodies entirely and reporting only validated version identifiers plus a canonical `https://github.com/<owner>/<repo>/releases` URL. 7. Add tests containing malicious examples such as remote images, phishing links, headings, tables, nested formatting, and control characters. 8. Document that changelog text originates from an external repository and is not trusted by the Skill. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The core purpose partially matches: the script does check container image versions and reports whether updates are available. However, several important declared capabilities are absent. There is no implementation for fetching release notes, changelogs, or comparing update safety beyond a simple semantic version bump type. It also does not prioritize updates in any explicit way; it returns results in input order. Additionally, registry support is narrower than the description implies, since unsupported registries are skipped and GHCR is not actually queried in this code chunk despite constants suggesting it. Therefore the description overstates the behavior in material ways.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The supplied code chunk is a helper script focused narrowly on changelog retrieval from GitHub. It does not inspect Docker containers, compare local versus remote image versions, or decide what needs updating. It also does not analyze release notes to classify breaking changes or safe updates, nor does it prioritize updates. While fetching release notes is consistent with part of the declared description, the primary declared purpose is much broader than this code’s actual behavior. Therefore the description does not accurately represent this code chunk on its own.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code's actual function is limited to local inventory of running Docker containers and parsing their image identifiers. While this could support a later update-check workflow, the declared description claims substantially more functionality: determining whether newer image versions exist, generating a prioritized update report, fetching release notes, and classifying updates by risk. None of those behaviors are implemented in the supplied code. Resource access is limited to the local Docker daemon, whereas the declared purpose implies external registry and release-note lookups. This is a material description-to-behavior mismatch.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes shell commands, inspects running Docker containers, reads environment variables, and makes outbound network requests, but it declares no explicit tool scope or permissions. This creates an authorization and transparency gap: an agent may execute host-inspection and external connectivity operations without clear policy boundaries or user-visible consent expectations.

Vague Triggers

Medium
Confidence
95% confidence
Finding
Broad trigger phrases can cause the skill to activate on generic Docker or update-related requests, leading to unintended execution of shell-based host inspection and outbound API calls. In agentic environments, overbroad invocation increases the chance of surprising data exposure, unnecessary network access, or tool use without the user's informed intent.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The description omits that the skill inspects the local Docker runtime and contacts external services like Docker Hub and GitHub. Lack of disclosure undermines informed consent and can expose metadata about deployed containers or consume credentials/API quota unexpectedly, especially in sensitive or regulated environments.

Session Persistence

Medium
Category
Rogue Agent
Content
Run nightly via cron and save the report to the workspace:

```bash
# Edit crontab: crontab -e
0 7 * * * cd ~/.openclaw/workspace/skills/container-update-advisor/scripts && python3 scan_containers.py | python3 check_updates.py | python3 fetch_changelog.py | python3 format_report.py > ~/container-updates-$(date +\%Y-\%m-\%d).md 2>&1
```
Confidence
85% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest says the skill checks running Docker containers for newer image versions, fetches release notes, and flags breaking changes versus safe updates. In this file, non-Docker Hub registries are explicitly skipped, and the code only compares version tags and returns simple bump metadata; there is no GHCR support here and no release-note or breaking-change retrieval logic.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def check_docker():
    try:
        result = subprocess.run(
            ["docker", "info"],
            capture_output=True, text=True, timeout=10
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
'"status":"{{.Status}}",'
        '"created":"{{.CreatedAt}}"}'
    )
    result = subprocess.run(
        ["docker", "ps", "--format", format_str],
        capture_output=True, text=True, timeout=15
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Low
Confidence
85% confidence
Finding
This markdown file includes cron examples that automatically write reports into the user's home directory and Obsidian vault. While the writes are part of the skill's purpose, the guide does not disclose that these scheduled outputs persist system/container metadata to disk and may overwrite existing same-named files for a given date.

Static analysis

No suspicious patterns detected.