Back to skill

Security audit

Disk Guardian

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent disk-health scanner, but its optional sudo mode can run a PATH-selected smartctl binary with elevated privileges.

Review before installing. Use non-sudo mode when possible, and do not run --sudo unless you have verified smartctl is the real system binary from a trusted path. Be aware that optional history logging records drive identifiers such as model and serial number under ~/.openclaw/workspace/disk-guardian/.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/scan_drives.py:21
Finding

Caller-Controlled PATH Can Select an Executable That Is Subsequently Run Through sudo

Content
View full analysis

Vulnerability Details

File Location: scripts/scan_drives.py, lines 21–32 and 108–116
Vulnerability Type: Privilege escalation through unsafe executable resolution
Risk Level: High

Vulnerable Code

python
def find_smartctl():
    """Return path to smartctl or None if not found."""
    candidates = [
        shutil.which("smartctl"),
        "/usr/local/sbin/smartctl",
        "/opt/homebrew/sbin/smartctl",
        "/usr/sbin/smartctl",
    ]
    for path in candidates:
        if path and Path(path).exists():
            return path
    return None
python
def run_smartctl(device, smartctl_path, use_sudo=False):
    """Run smartctl -a on a device. Returns (output_str, error_str)."""
    cmd = []
    if use_sudo:
        cmd.append("sudo")
    cmd += [smartctl_path, "-a", device]

    try:
        result = subprocess.run(
            cmd,
            capture_output=True, text=True, timeout=30
        )

Technical Analysis

find_smartctl() gives precedence to shutil.which("smartctl"), which searches the caller-controlled PATH. The selected path is accepted merely when it exists; the code does not verify that it is a regular trusted executable, is owned by a privileged account, or is not writable by an untrusted user.

When the documented --sudo option is enabled, run_smartctl() passes that resolved path to sudo. Although the use of an argument array prevents shell metacharacter injection, it does not prevent executable substitution. An attacker who controls the environment or can place a malicious smartctl in an earlier PATH directory can cause their program to be selected and offered for privileged execution.

The attack still depends on the applicable sudo policy or a user successfully authorizing the sudo prompt. It is therefore not an authentication bypass by itself, but it creates an unsafe privilege boundary in the documented elevated workflow.

Attack Path

  1. The attacker creates an executable nam ...[truncated 1167 chars]
Remediation
View remediation

Remediation Suggestions

  1. Do not use a caller-controlled PATH to resolve an executable that will be run through sudo.
  2. Under --sudo, select only explicit trusted installation paths appropriate to the operating system, such as /usr/sbin/smartctl, after validation.
  3. Validate the selected path with Path.resolve() and stat():
    • Require a regular file.
    • Reject symbolic links where practical.
    • Require ownership by root or another explicitly trusted administrator.
    • Reject files writable by group or other users.
  4. Avoid trusting /usr/local or Homebrew paths for privileged execution unless their complete directory chain and file ownership are verified.
  5. Run with a sanitized environment and an explicit safe PATH, for example by using an administrative wrapper with a tightly scoped sudoers rule.
  6. Prefer granting only the minimum capability necessary to a verified smartctl binary rather than elevating an executable selected by application logic.
  7. If no trusted binary passes validation, stop with an error instead of falling back to shutil.which().
  8. Add tests that place a fake smartctl first in PATH and verify that elevated mode rejects it.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (32)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The supplied code is a parser/assessor for smartctl output, not a full drive-diagnostics workflow. It reads already-collected SMART data, parses SATA and NVMe attributes, computes simple warning/critical flags, and emits JSON. While this partially supports the declared domain of disk health checking, several central claims in the description are not implemented in this chunk: there is no code to invoke smartctl, enumerate all drives, persist historical results, compare across runs for early failure patterns, or rank drives by risk. The code is consistent with a subcomponent of such a skill, but by itself it does not accurately match the broader declared functionality.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code aligns with part of the description in that it scans drives on macOS/Linux and runs SMART diagnostics via smartctl. However, the description claims substantially more post-processing and analysis than the code actually performs. The implementation only enumerates drives, executes smartctl -a, and returns raw output or errors in JSON. There is no logic to extract health metrics, interpret SMART attributes, store historical results, compare over time, flag early failure patterns, or produce ranked risk reports. So the declared description overstates the actual behavior in material ways.

Content

No source excerpt is available for this finding.

Privileged Container / Container Escape

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Potential security issue detected. Manual review is recommended.

Content

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

md
python3 history.py --record --input parsed.json

    # View trend analysis:
    python3 history.py --trends [--device /dev/disk0]

    # List history:
    python3 history.py --list [--device /dev/disk0] [--limit 10]

Privileged Container / Container Escape

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Potential security issue detected. Manual review is recommended.

Content

Scanner excerpt · scripts/history.py (reported line 13)May include surrounding context.

python
python3 history.py --record --input parsed.json

    # View trend analysis:
    python3 history.py --trends [--device /dev/disk0]

    # List history:
    python3 history.py --list [--device /dev/disk0] [--limit 10]

Privileged Container / Container Escape

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Potential security issue detected. Manual review is recommended.

Content

Scanner excerpt · scripts/history.py (reported line 16)May include surrounding context.

python
python3 history.py --record --input parsed.json

    # View trend analysis:
    python3 history.py --trends [--device /dev/disk0]

    # List history:
    python3 history.py --list [--device /dev/disk0] [--limit 10]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documentation describes shell execution, file reads, and file writes, but it declares no explicit tool scope or permissions boundary. That creates an authorization ambiguity where an agent may invoke filesystem and shell-capable behavior without clear least-privilege constraints or user-visible consent expectations.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger description is extremely broad and overlaps with common user phrasing about disk health, increasing the chance of automatic invocation in contexts where the user did not explicitly consent to a host-level disk scan. In this skill, unintended invocation is more sensitive because it can enumerate hardware, run shell commands, and persist scan history.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
83% confidence
Finding

The skill explicitly anticipates operations that may require sudo, meaning an agent using it could prompt or lead users into running privileged hardware interrogation commands. While SMART reads are often legitimate, coupling broad invocation with possible privilege escalation increases risk if executed in the wrong environment or with modified scripts.

Content

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

bash
cd ~/.openclaw/workspace/skills/disk-guardian/scripts

# Full pipeline (may need sudo on Linux):
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
83% confidence
Finding

The skill explicitly anticipates operations that may require sudo, meaning an agent using it could prompt or lead users into running privileged hardware interrogation commands. While SMART reads are often legitimate, coupling broad invocation with possible privilege escalation increases risk if executed in the wrong environment or with modified scripts.

Content

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

bash
cd ~/.openclaw/workspace/skills/disk-guardian/scripts

# Full pipeline (may need sudo on Linux):
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
88% confidence
Finding

The documented --sudo mode directly supports running the scan pipeline with elevated privileges. Even if intended for legitimate SMART access, privileged execution materially raises the blast radius of any script defect, path hijack, or future modification in the referenced scripts.

Content

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

md
# Full pipeline (may need sudo on Linux):
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:
python3 scan_drives.py | python3 parse_smart.py | python3 report.py --output ~/disk-report.md

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:
python3 scan_drives.py | python3 parse_smart.py | python3 report.py --output ~/disk-report.md

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 143)May include surrounding context.

python
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:
python3 scan_drives.py | python3 parse_smart.py | python3 report.py --output ~/disk-report.md

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 167)May include surrounding context.

python
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:
python3 scan_drives.py | python3 parse_smart.py | python3 report.py --output ~/disk-report.md

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 186)May include surrounding context.

python
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:
python3 scan_drives.py | python3 parse_smart.py | python3 report.py --output ~/disk-report.md

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 188)May include surrounding context.

python
python3 scan_drives.py | python3 parse_smart.py | python3 report.py

# With sudo (required on many Linux systems):
python3 scan_drives.py --sudo | python3 parse_smart.py | python3 report.py

# Save report to file:
python3 scan_drives.py | python3 parse_smart.py | python3 report.py --output ~/disk-report.md

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill specifies a feature that prepends sudo to smartctl commands. This is not inherently malicious, but it creates a privileged execution path that should be treated carefully because the skill also relies on shell command composition and host device enumeration.

Content

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

md
### scan_drives.py
- macOS: uses `diskutil list` to find whole disks, then `smartctl -a /dev/diskN`
- Linux: uses `lsblk` to find block devices, then `smartctl -a /dev/sdX`
- `--sudo`: prepend sudo to smartctl commands (needed on Linux without udev rules)
- Outputs JSON: `{os, smartctl_path, drives_found, scan_results: [{device, smartctl_output|error}]}`

### parse_smart.py

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script persists disk serial numbers and models into a history file under the user's home directory without any notice, consent, or minimization. Drive serials are device identifiers that can be sensitive in enterprise, forensic, or privacy-sensitive environments because they enable host/device correlation and inventory tracking if the file is exposed.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
50% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/report.py (reported line 122)May include surrounding context.

python
"Continue regular monthly SMART scans.",
    ],
    "Unknown": [
        "Check SMART support and permissions (may need sudo).",
        "Ensure smartctl is installed and up to date.",
    ],
}

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

python
import subprocess as _sp, sys as _sys
                history_script = Path(__file__).parent / "history.py"
                if history_script.exists():
                    result = _sp.run(
                        [_sys.executable, str(history_script), "--trends",
                         "--data-dir", str(data_dir)],
                        capture_output=True, text=True, timeout=10

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

python
def detect_drives_macos():
    """Return list of disk device paths using diskutil list."""
    try:
        result = subprocess.run(
            ["diskutil", "list", "-plist"],
            capture_output=True, text=True, timeout=15
        )

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 40)May include surrounding context.

python
"""Return list of disk device paths using diskutil list."""
    try:
        result = subprocess.run(
            ["diskutil", "list", "-plist"],
            capture_output=True, text=True, timeout=15
        )
        if result.returncode != 0:

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 46)May include surrounding context.

python
"""Return list of disk device paths using diskutil list."""
    try:
        result = subprocess.run(
            ["diskutil", "list", "-plist"],
            capture_output=True, text=True, timeout=15
        )
        if result.returncode != 0:

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 47)May include surrounding context.

python
"""Return list of disk device paths using diskutil list."""
    try:
        result = subprocess.run(
            ["diskutil", "list", "-plist"],
            capture_output=True, text=True, timeout=15
        )
        if result.returncode != 0:

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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.

Content

Scanner excerpt · scripts/scan_drives.py (reported line 48)May include surrounding context.

python
"""Return list of disk device paths using diskutil list."""
    try:
        result = subprocess.run(
            ["diskutil", "list", "-plist"],
            capture_output=True, text=True, timeout=15
        )
        if result.returncode != 0: