Back to skill

Security audit

Unraid Monitor Skill for OpenClaw

Security checks for vulnerabilities and agentic risk

Overview

This Unraid monitoring skill appears purpose-aligned, but it handles server credentials and scheduling in ways users should review carefully before installing.

Install only after reviewing the credential and scheduling risks. Use HTTPS only, avoid optional session cookies unless required, verify any self-signed certificate fingerprint out of band, do not install unverified certificates system-wide, create a real .gitignore before making .env, keep .env and .state private, and install cron entries manually or with a safe temporary file workflow.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/unraid_common.sh:14
Finding

API credentials can be transmitted over plaintext HTTP

Content
View full analysis
"$err_file" ``` ### Technical Analysis The base URL validation explicitly accepts both `http://` and `https://`. When HTTP is selected, the script sends the Unraid API key and, if configured, the CSRF token and session cookie without transport encryption. The headers are transmitted on every GraphQL request. HTTP provides neither confidentiality nor server authentication, allowing an attacker with a network observation or interception position to recover or modify the request. ### Attack Path 1. The operator configures `UNRAID_BASE_URL` with an `http://` URL. 2. A manual check or scheduled monitoring execution invokes `graphql_post`. 3. The script includes the API key and optional session credentials in HTTP headers. 4. An attacker on the same network segment, compromised router, proxy, or Wi-Fi access point captures the plaintext request. 5. The attacker reuses the recovered credentials against the Unraid API. ### Impact Assessment An attacker can obtain the configured API key, CSRF token, or session cookie. The resulting access is limited by the permissions assigned to those credentials, but may include visibility into sensitive server, array, disk, and container information. If an overly privileged API key is used, the compromise could extend beyond the read-only op ...[truncated 41 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/unraid_common.sh:79
Finding

Unescaped environment values permit curl configuration directive injection

Content
View full analysis
&2; return 1; } chmod 600 "$config_file" || { rm -f "$config_file"; return 1; } trap "rm -f '$config_file'" RETURN # Write headers to config file (more secure than command-line arguments) { echo "header = \"Content-Type: application/json\"" printf "header = \"x-api-key: %s\"\n" "$UNRAID_API_KEY" echo "header = \"X-Requested-With: XMLHttpRequest\"" if [[ -n "$csrf_token" ]]; then printf "header = \"X-CSRF-TOKEN: %s\"\n" "$csrf_token" fi if [[ -n "$session_cookie" ]]; then printf "header = \"Cookie: %s\"\n" "$session_cookie" fi } > "$config_file" curl_args=( -sS --config "$config_file" --connect-timeout "$timeout" --max-time "$timeout" -o "$body_file" -w "%{http_code}" -X POST "$ep" ) curl "${curl_args[@]}" --data "$query_json" 2>"$err_file" ``` ### Technical Analysis The API key, CSRF token, and session cookie are interpolated directly into curl configuration-file syntax. The script does not reject carriage returns, newlines, quotation marks, backslashes, or control characters. A crafted multiline environment value can terminate the intended `header` entry and add another curl configuration directive. Depending on the injected directives and curl behavior, this can modify request destinations or other transfer properties. Because the authentication headers are loaded globally from the same configuration file, an injected additional URL may receive sensitive headers. The temporary file itself is created securely; the flaw is the absence of curl-config-specific input validation and escaping. ### Attack Path 1. An attacker influences one of `UNRAI ...[truncated 945 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:149
Finding

Predictable shared temporary file permits crontab tampering and file clobbering

Content
View full analysis
/tmp/current.cron 2>/dev/null || true cat /tmp/current.cron scripts/unraid_monitor.cron.template | crontab - ``` ### Technical Analysis The documented installation procedure uses the fixed path `/tmp/current.cron`. Shared temporary directories are normally writable by all local users. The command does not use exclusive creation, validate the file type or ownership, restrict permissions, or remove the file afterward. A local attacker can pre-create this path as a symbolic link, causing the shell redirection to truncate another file writable by the victim. An attacker may also race or replace the temporary file before it is passed to `crontab -`, introducing attacker-controlled scheduled commands. The referenced `scripts/unraid_monitor.cron.template` is absent from the audited project, making the workflow incomplete and increasing the chance that users improvise an unsafe replacement. ### Attack Path 1. A local attacker anticipates that a user will follow the documented setup procedure. 2. The attacker creates `/tmp/current.cron` as a symlink to a file writable by the victim, or prepares to replace the temporary file after creation. 3. The victim executes the first command, potentially truncating the symlink target. 4. Before the second command reads the file, the attacker replaces its contents with a malicious cron entry. 5. The combined content is installed through `crontab -`. 6. The malicious command subsequently runs under the victim user's account according to its schedule. ### Impact Assessment A successful cron race can provide recurring command execution with all privileges of the user who installs the crontab. The symlink variant can overwrite or truncate files writable by that user. It does not directly provide root privileges unless the workflow is e ...[truncated 93 chars]
Remediation
View remediation
"$tmp" 2>/dev/null || true cat "$tmp" scripts/unraid_monitor.cron.template | crontab - ``` - Prefer constructing and validating one exact cron entry rather than concatenating an entire untrusted file. - Check whether the entry already exists to prevent duplicate schedules. - Clearly instruct users not to run the installation as root unless root-level monitoring is explicitly required. - Ship the documented `scripts/unraid_monitor.cron.template`, or remove references to it. - Provide a safe uninstall command that removes only the exact project entry and preserves unrelated crontab content. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
README.md:48
Finding

Unauthenticated certificate retrieval is followed by system-wide trust installation

Content
View full analysis
:443 /dev/null | openssl x509 -outform PEM > unraid-selfsigned.crt ``` ```bash sudo cp unraid-selfsigned.crt /usr/local/share/ca-certificates/unraid-selfsigned.crt ``` ```bash sudo update-ca-certificates ``` Related Skill instruction: ```text Self-signed TLS certificate: prompt the user to allow installation/trust of the server certificate, then retry. ``` ### Technical Analysis The procedure retrieves a certificate over an unauthenticated connection and immediately instructs the user to install it into the operating system trust store with root privileges. No certificate fingerprint, public-key hash, hostname verification, or other out-of-band validation is required. An attacker controlling DNS, local routing, a gateway, or the network path during the initial retrieval can substitute a different certificate. Adding a certificate to the system trust store grants broader authority than necessary for a single monitoring client. If the installed certificate is accepted as a CA certificate, unrelated system applications may also trust certificates issued by the attacker's key. ### Attack Path 1. The operator encounters a self-signed certificate error. 2. An attacker gains a network interception position or poisons hostname resolution. 3. The operator runs the documented `openssl s_client` command. 4. The attacker supplies a substitute certificate. 5. The operator installs the unverified certificate into the system trust store using `sudo`. 6. Subsequent connections trust the attacker-controlled certificate. 7. The attacker intercepts future API requests and may recover authentication headers. ### Impact Assessment The procedure can weaken trust decisions system-wide, exceeding the privileges needed for this mon ...[truncated 245 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/unraid_common.sh:48
Finding

Infrastructure snapshots and logs are created without restrictive permissions

Content
View full analysis
> "$run_log" } ``` ### Technical Analysis The project does not set a restrictive `umask` or explicitly assign secure modes to state directories, snapshots, or logs. Under a common `022` umask, directories may be created as `0755` and files as `0644`. Snapshots contain operational information including the configured endpoint, operating-system details, disk names and status, Docker container IDs, names, images, and runtime state. Logs contain monitoring status and failure details. Although API credentials are not intentionally written to these files, the stored infrastructure inventory is security-sensitive. ### Attack Path 1. Monitoring runs under a normal multi-user account with a permissive umask. 2. `ensure_state_dirs` creates the state hierarchy with group/world traversal permissions. 3. Snapshot and log files are copied or created with group/world read permissions. 4. Another local user enumerates and reads the files. 5. The user obtains infrastructure details useful for reconnaissance or targeted attacks. ### Impact Assessment The issue exposes local infrastructure inventory to other accounts on the same machine. It does not directly disclose the API key in the reviewed implementation, but container names, images, disk status, endpoin ...[truncated 73 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:27
Finding

Documented secret-protection files are absent from the project

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (22)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 62)May include surrounding context.

md
## Setup

1. Create your local environment file:
   cp .envexample .env

2. Edit .env and set your values:
   UNRAID_BASE_URL=https://tower.local

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 64)May include surrounding context.

md
## Setup

1. Create your local environment file:
   cp .envexample .env

2. Edit .env and set your values:
   UNRAID_BASE_URL=https://tower.local

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 73)May include surrounding context.

md
## Setup

1. Create your local environment file:
   cp .envexample .env

2. Edit .env and set your values:
   UNRAID_BASE_URL=https://tower.local

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
## Setup

1. Create your local environment file:
   cp .envexample .env

2. Edit .env and set your values:
   UNRAID_BASE_URL=https://tower.local

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
## Setup

1. Create your local environment file:
   cp .envexample .env

2. Edit .env and set your values:
   UNRAID_BASE_URL=https://tower.local

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code shown is an alert/reporting script, not a live read-only GraphQL query tool. It requires jq, locates a local snapshot file, fails if the snapshot is missing, calls a helper to compute health status from the snapshot, outputs either human-readable alerts or JSON, and returns severity-based exit codes. While it may be related to Unraid monitoring, its primary behavior is local snapshot analysis and alert generation rather than querying an Unraid server via GraphQL for current status. This is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description says the skill queries an Unraid server via GraphQL for system, array, and Docker status in read-only mode. This script instead depends on an existing snapshot file generated elsewhere, validates that file exists, and uses jq to extract array, parity, and disk fields from the JSON. Its primary purpose is a local parity/array report, optionally in JSON. While it is read-only, the access pattern and scope are materially different from the declaration: no direct server query is performed in this chunk, GraphQL is not used here, and system/Docker status are not covered.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The code is read-only and does query an Unraid GraphQL endpoint, which is consistent in broad resource access. However, the implemented behavior is narrower and materially different from the declared description: it performs a connection/auth smoke test using a minimal HealthCheck query and returns diagnostic pass/fail information. It does not retrieve array status or Docker status as claimed, and its main function is validating reachability/authentication rather than reporting system, array, and Docker status.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says the skill queries an Unraid server via GraphQL in read-only mode for status information. This code chunk does not show GraphQL querying at all; instead, it acts as a cron runner coordinating several other scripts for preflight, snapshot, summary, alerts, and notifications. It also writes logs and triggers notifications, which are operational side effects beyond a read-only query description. While some of the invoked scripts may ultimately gather status data, the primary behavior of this chunk is workflow orchestration and alerting, so the supplied description does not accurately represent this code.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description says the skill queries an Unraid server via GraphQL for system, array, and Docker status in read-only mode. The provided code instead loads a previously generated local snapshot file, uses jq to extract Docker-related fields, and prints a Docker-only report. While this is still read-only and related to Unraid status, the primary behavior is materially narrower and different: no direct server access, no GraphQL activity, and no system or array reporting in this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description says the skill queries an Unraid server via GraphQL in read-only mode for system, array, and Docker status. This script does not perform any network or GraphQL operations. Instead, it requires jq, finds the latest local snapshot file, fails if that snapshot does not exist, computes health status from the snapshot using sourced helper functions, and formats the results as either JSON or human-readable output. While the data fields summarized align with system/array/Docker status and the behavior appears read-only, the primary mechanism and purpose differ materially: this is a local snapshot health summarizer, not a direct GraphQL query tool.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says this skill queries an Unraid server via GraphQL in read-only mode to retrieve status information. The provided code does not perform any network access, GraphQL query, or status retrieval. Its primary purpose is local notification logging: it takes input parameters, builds a timestamped log line, and appends it to a local file. This is a materially different behavior and involves filesystem write access, which is inconsistent with the declared read-only query purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description says the skill queries an Unraid server via GraphQL to retrieve system, array, and Docker status in read-only mode. The supplied code chunk does not perform any GraphQL query or retrieve those statuses. Instead, it validates prerequisites (base URL, API key, timeout, curl), optionally checks for jq, and invokes a separate connection test script. That is a materially different primary purpose: setup/preflight and connectivity validation rather than status querying. While these actions may support a querying skill, this code chunk itself is not accurately represented by the declared description.

Content

No source excerpt is available for this finding.

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 · README.md (reported line 51)May include surrounding context.

md
1. Export the server certificate:
   `openssl s_client -showcerts -connect <UNRAID_HOST>:443 </dev/null 2>/dev/null | openssl x509 -outform PEM > unraid-selfsigned.crt`
2. Install it into the system trust store:
   `sudo cp unraid-selfsigned.crt /usr/local/share/ca-certificates/unraid-selfsigned.crt`
3. Refresh trust store:
   `sudo update-ca-certificates`
4. Re-run connection test:

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 · README.md (reported line 53)May include surrounding context.

md
1. Export the server certificate:
   `openssl s_client -showcerts -connect <UNRAID_HOST>:443 </dev/null 2>/dev/null | openssl x509 -outform PEM > unraid-selfsigned.crt`
2. Install it into the system trust store:
   `sudo cp unraid-selfsigned.crt /usr/local/share/ca-certificates/unraid-selfsigned.crt`
3. Refresh trust store:
   `sudo update-ca-certificates`
4. Re-run connection test:

Session Persistence

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

Content

Scanner excerpt · README.md (reported line 151)May include surrounding context.

md
2. Keep only one schedule line (15m recommended, or 5m for tighter monitoring).
3. Install the line into your crontab:

   crontab -l > /tmp/current.cron 2>/dev/null || true
   cat /tmp/current.cron scripts/unraid_monitor.cron.template | crontab -

Verify cron output:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares network and shell-capable behavior but does not define an explicit tool scope such as allowed-tools or permissions. In an agent environment, that can cause the runtime to grant broader-than-necessary execution authority, increasing the blast radius if the skill is invoked unexpectedly or modified later.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

Scanner excerpt · scripts/unraid_common.sh (reported line 81)May include surrounding context.

sh
# Create secure temporary config file for curl (keeps API key out of process list)
  config_file=$(mktemp) || { echo "Failed to create temp config file for curl" >&2; return 1; }
  chmod 600 "$config_file" || { rm -f "$config_file"; return 1; }
  trap "rm -f '$config_file'" RETURN

  # Write headers to config file (more secure than command-line arguments)

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/unraid_common.sh (reported line 107)May include surrounding context.

sh
-X POST "$ep"
  )

  curl "${curl_args[@]}" --data "$query_json" 2>"$err_file"
}

compute_health_status_from_snapshot() {

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script performs outbound notification actions via unraid_notify.sh on multiple execution paths, which exceeds the declared skill scope of read-only GraphQL status querying. Even if the notifications are operationally useful, this is a capability mismatch: a user or platform trusting the skill as read-only may unknowingly grant or execute side-effecting behavior such as sending alerts to external systems.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

A notification capability is not clearly justified by the stated purpose of a read-only status-query skill, creating a transparency and trust problem. Hidden or under-declared egress paths can be abused for data exfiltration, spam, or unexpected integrations, and the danger is increased here because the runner automatically triggers notifications on failures and alert states without an explicit user action in this file.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest frames the skill as a read-only query mechanism for Unraid status, but this script also stores the retrieved data as both a latest snapshot and an archived snapshot on the local filesystem. While it does not modify the Unraid server, it performs additional stateful local persistence beyond mere querying.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.