Back to skill

Security audit

Ops Hygiene

Security checks for vulnerabilities and agentic risk

Overview

This maintenance skill is not clearly malicious, but it mixes routine health checks with automatic email/API-key use and broad host/workspace inspection that merits Review before installation.

Install only if you want an agent-maintenance skill that can run shell scripts, inspect the local OpenClaw workspace and parts of the host, write maintenance state/memory, and use local services. Before enabling recurring heartbeat use, remove or configure the hard-coded AgentMail inbox, require explicit consent for using secrets from .secrets, restrict auditing to approved paths, and treat the bundled security-audit results as advisory until the script bugs are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/heartbeat-dispatch.sh:35
Finding

Python Code Injection Through Unescaped Filesystem Paths

Content
View full analysis
/dev/null || echo "0" else echo "0" fi } update_state() { local key="$1" python3 -c " import json, os path = '$STATE_FILE' os.makedirs(os.path.dirname(path), exist_ok=True) try: with open(path) as f: d = json.load(f) except: d = {'lastChecks': {}} d.setdefault('lastChecks', {})['$key'] = $NOW with open(path, 'w') as f: json.dump(d, f, indent=2) " 2>/dev/null } ``` ```bash CONFIG="$HOME/.openclaw/openclaw.json" if [ -f "$CONFIG" ]; then # Check if elevated commands are restricted ELEVATED=$(python3 -c " import json with open('$CONFIG') as f: c = json.load(f) sec = c.get('security', {}) elevated = sec.get('elevated', 'unknown') print(f'elevated={elevated}') " 2>/dev/null || echo "error reading config") ``` ### Technical Analysis Paths derived from the shell environment are embedded directly into Python source code passed to `python3 -c`. In particular, `STATE_FILE` and `CONFIG` are derived from the value of `HOME`. Shell expansion does not sanitize quotes contained in variable values. If a path contains a single quote, that quote becomes part of the generated Python program and can terminate the Python string literal. An attacker who controls the execution environment can append Python statements and comment out the remaining generated source. The `key` argument is interpolated using the same unsafe technique. Current call sites use fixed internal key names, which reduces immedia ...[truncated 1466 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/security-audit.sh:20
Finding

Security Audit Reports Detected Secrets as Clean

Content
View full analysis
&1 | grep -q "🔴"; then log " ⚠️ SECRETS FOUND — see secret-scan output" ISSUES=$((ISSUES + 1)) else log " ✅ No secrets in workspace" fi ``` The invoked scanner explicitly returns status 1 when it detects secrets: ```bash if [ "$FOUND" -eq 1 ]; then echo "🔴 Secrets detected — review and clean up!" exit 1 else echo "✅ No secrets found — workspace is clean" exit 0 fi ``` ### Technical Analysis The audit enables `set -euo pipefail`. With `pipefail`, a pipeline returns a failure status when any component fails, rather than returning only the status of its final command. `secret-scan.sh` intentionally exits with status 1 when it detects a secret. Consequently, even when `grep -q "🔴"` finds the expected marker, the pipeline remains unsuccessful because the scanner returned 1. The `if` condition therefore selects the `else` branch and prints `No secrets in workspace`. Using human-readable output and an emoji as the machine-readable security decision also makes the integration brittle. Changes in output wording, encoding, or locale can produce additional false results. ### Attack Path 1. A credential matching one of the scanner patterns is stored in the workspace. 2. The monthly security audit invokes `secret-scan.sh`. 3. The scanner correctly detects the credential, prints the red warning marker, and exits with status 1. 4. Because `pipefail` is active, the complete pipeline returns a nonzero status. 5. The audit enters the `else` branch. 6. The audit reports that no secrets exist and does not increment `ISSUES`. 7. An operator relying on the summary may leave the exposed credential active and present in the wo ...[truncated 477 chars]
Remediation
View remediation
&1) SCAN_STATUS=$? set -e case "$SCAN_STATUS" in 0) log " ✅ No secrets in workspace" ;; 1) log " ⚠️ SECRETS FOUND — review scanner output" ISSUES=$((ISSUES + 1)) ;; *) log " 🔴 Secret scanner failed with status $SCAN_STATUS" ISSUES=$((ISSUES + 1)) ;; esac ``` Further hardening should include: 1. Do not parse decorative text or emojis to determine security status. 2. Provide a structured output mode, such as JSON, if detailed results are needed. 3. Distinguish scanner failure from a clean result. 4. Add regression tests for clean scans, detected secrets, unreadable directories, and scanner crashes. 5. Ensure the audit summary returns a nonzero status for both findings and incomplete scans. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/secret-scan.sh:46
Finding

Secret Scanner Excludes Files Likely to Contain Credentials

Content
View full analysis
/dev/null || true) ``` The later filename check does not compensate for all excluded file types: ```bash sensitive_files=$(find "$TARGET" -maxdepth 4 \ \( -name ".env" -o -name ".env.local" -o -name "*.pem" -o -name "*.key" \ -o -name "id_rsa" -o -name "id_ed25519" -o -name "credentials.json" \) \ -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null || true) ``` ### Technical Analysis The content scan excludes all `.log` and `.jsonl` files as well as `auth-profiles.json`. Logs and transcript-like JSONL files commonly receive credentials through diagnostic output, request serialization, copied command lines, exception messages, or agent conversations. A file named `auth-profiles.json` is also intrinsically likely to contain authentication material. The scanner subsequently checks only a fixed set of sensitive filenames. That check does not include arbitrary `.log` or `.jsonl` files or `auth-profiles.json`, so credentials in those locations can produce a clean result. The scanner also suppresses all `grep` and `find` errors. Permission failures or malformed targets can therefore reduce coverage without causing an incomplete-scan warning. ### Attack Path 1. A credential is accidentally written to a `.log`, `.jsonl`, or `auth-profiles.json` file. 2. The scanner applies its global exclusion list. 3. No content inspection is performed on the affected file. 4. The secondary ...[truncated 772 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Note
Location
scripts/security-audit.sh:27
Finding

Maintenance Scripts Perform Broad Host Reconnaissance Beyond a Minimal Heartbeat

Content
View full analysis
/dev/null | while read -r f; do if [ -f "$f" ]; then perms=$(stat -f "%Lp" "$f" 2>/dev/null || stat -c "%a" "$f" 2>/dev/null) if [ "${perms: -1}" != "0" ]; then echo "$f ($perms)" fi fi done) ``` ```bash # 4. OpenClaw config review log "▸ 4. OPENCLAW CONFIG" CONFIG="$HOME/.openclaw/openclaw.json" ``` ```bash # 5. Open ports log "▸ 5. NETWORK EXPOSURE" LISTENING=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | grep -v "^COMMAND" | awk '{print $1, $9}' | sort -u || echo "none") ``` ```bash # 7. Stale sessions log "▸ 7. STALE PROCESSES" STALE=$(ps aux | grep -E "[n]ode server|[p]ython.*serve" | grep -v grep || true) ``` The health check also enumerates broad process information: ```bash # Stale processes BG_COUNT=$(ps aux | grep -c "[n]ode\|[p]ython3\|[o]llama" || echo 0) echo " \"backgroundProcesses\": $BG_COUNT," ``` ### Technical Analysis The declared comprehensive monthly security audit reasonably requires some host inspection. However, the implementation enumerates system-wide process details, all listening TCP services, OpenClaw security configuration, and sensitive filenames. The health check also uses `ps aux`, which can expose information about processes owned by users other than the Skill's account. These commands do not elevate privileges and no external exfiltration path was found. The risk arises because the resulting reports provide useful reconnaissance if they are exposed to an untrusted caller, retained in insecure logs, or passed to a compromised downstream component. The broad monthly audit ...[truncated 1383 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The stated purpose suggests ordinary housekeeping, but the content expands into email access, message triage, use of external or local LLM services, secret-dependent resource access, and autonomous escalation behavior. This mismatch is dangerous because users or orchestrators may grant or invoke the skill under a lower-risk assumption, while it actually processes sensitive communications and can trigger broader actions than expected.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/health-check.sh (reported line 37)May include surrounding context.

sh
echo "  \"cpu\": {\"load1m\": $LOAD, \"cores\": $CPU_COUNT},"

# Ollama status
if curl -s --max-time 2 http://localhost:11434/api/tags > /dev/null 2>&1; then
    MODEL_COUNT=$(curl -s http://localhost:11434/api/tags | python3 -c "import sys,json; print(len(json.load(sys.stdin).get('models',[])))" 2>/dev/null || echo 0)
    LOADED=$(curl -s http://localhost:11434/api/ps | python3 -c "import sys,json; models=json.load(sys.stdin).get('models',[]); print(models[0]['name'] if models else 'none')" 2>/dev/null || echo "unknown")
    echo "  \"ollama\": {\"running\": true, \"models\": $MODEL_COUNT, \"loaded\": \"$LOADED\"},"

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/health-check.sh (reported line 39)May include surrounding context.

sh
# Ollama status
if curl -s --max-time 2 http://localhost:11434/api/tags > /dev/null 2>&1; then
    MODEL_COUNT=$(curl -s http://localhost:11434/api/tags | python3 -c "import sys,json; print(len(json.load(sys.stdin).get('models',[])))" 2>/dev/null || echo 0)
    LOADED=$(curl -s http://localhost:11434/api/ps | python3 -c "import sys,json; models=json.load(sys.stdin).get('models',[]); print(models[0]['name'] if models else 'none')" 2>/dev/null || echo "unknown")
    echo "  \"ollama\": {\"running\": true, \"models\": $MODEL_COUNT, \"loaded\": \"$LOADED\"},"
else
    echo "  \"ollama\": {\"running\": false},"

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/heartbeat-dispatch.sh (reported line 74)May include surrounding context.

sh
reef_triage() {
    local prompt="$1"
    local response
    response=$(curl -s --max-time 10 -X POST "${REEF_URL}/api/delegate" \
        -H "Content-Type: application/json" \
        -d "{\"prompt\": \"$prompt\"}" 2>/dev/null)

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 · scripts/secret-scan.sh (reported line 75)May include surrounding context.

sh
# Check for common secret file patterns
echo "📁 Checking for sensitive files..."
sensitive_files=$(find "$TARGET" -maxdepth 4 \
    \( -name ".env" -o -name ".env.local" -o -name "*.pem" -o -name "*.key" \
    -o -name "id_rsa" -o -name "id_ed25519" -o -name "credentials.json" \) \
    -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null || true)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/secret-scan.sh (reported line 76)May include surrounding context.

sh
echo "📁 Checking for sensitive files..."
sensitive_files=$(find "$TARGET" -maxdepth 4 \
    \( -name ".env" -o -name ".env.local" -o -name "*.pem" -o -name "*.key" \
    -o -name "id_rsa" -o -name "id_ed25519" -o -name "credentials.json" \) \
    -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null || true)

if [ -n "$sensitive_files" ]; then

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 · scripts/secret-scan.sh (reported line 75)May include surrounding context.

sh
# 2. File permissions
log "▸ 2. FILE PERMISSIONS"
WORLD_READABLE=$(find "$WORKSPACE" -maxdepth 3 -name ".secrets" -o -name ".env" -o -name "*.key" 2>/dev/null | while read -r f; do
    if [ -f "$f" ]; then
        perms=$(stat -f "%Lp" "$f" 2>/dev/null || stat -c "%a" "$f" 2>/dev/null)
        if [ "${perms: -1}" != "0" ]; then

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 · scripts/security-audit.sh (reported line 30)May include surrounding context.

sh
# 2. File permissions
log "▸ 2. FILE PERMISSIONS"
WORLD_READABLE=$(find "$WORKSPACE" -maxdepth 3 -name ".secrets" -o -name ".env" -o -name "*.key" 2>/dev/null | while read -r f; do
    if [ -f "$f" ]; then
        perms=$(stat -f "%Lp" "$f" 2>/dev/null || stat -c "%a" "$f" 2>/dev/null)
        if [ "${perms: -1}" != "0" ]; then

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs the agent to run shell scripts and update files such as memory logs and state JSON, but it does not declare any explicit tool scope or permissions boundaries. That makes the effective authority ambiguous and increases the chance the agent will execute file-write and shell actions more broadly than intended, especially because the skill is framed as routine maintenance and may be invoked frequently.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation language is very broad, covering periodic checks, security audits, memory maintenance, secret rotation, dependency updates, housekeeping, scheduling, and security posture questions. In context, that breadth is more dangerous because the skill also contains operational shell commands, file writes, and monitoring/escalation workflows, making over-invocation likely in situations where a narrower, less privileged skill should be used.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
77% confidence
Finding

This performs network transmission to a separate service boundary, which is security-relevant because the script is intended for routine maintenance and runs unattended. While the destination is localhost, that still exposes data to another process and expands the attack surface if the local service is compromised or spoofed.

Content

Scanner excerpt · scripts/heartbeat-dispatch.sh (reported line 74)May include surrounding context.

sh
reef_triage() {
    local prompt="$1"
    local response
    response=$(curl -s --max-time 10 -X POST "${REEF_URL}/api/delegate" \
        -H "Content-Type: application/json" \
        -d "{\"prompt\": \"$prompt\"}" 2>/dev/null)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script sends operational data to a local HTTP service without authentication, encryption, or meaningful disclosure. Even if the prompt currently contains only a message count, localhost services can be replaced, proxied, or monitored by other local processes, making this an avoidable data-flow and trust-boundary issue.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This maintenance script accesses a real email inbox and uses a secret-derived API key, which exceeds the minimally necessary scope implied by a housekeeping/heartbeat dispatcher. Even though it only counts messages, inbox access introduces unnecessary privilege and creates risk of unintended data exposure, account misuse, or future expansion into broader mailbox processing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script extracts an API key from a workspace secrets file and uses it automatically for mailbox access without explicit disclosure or consent at runtime. Silent use of stored secrets increases the chance of unauthorized account access, accidental privilege creep, and operational abuse if the workspace or script is tampered with.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/security-audit.sh (reported line 30)May include surrounding context.

sh
# 2. File permissions
log "▸ 2. FILE PERMISSIONS"
WORLD_READABLE=$(find "$WORKSPACE" -maxdepth 3 -name ".secrets" -o -name ".env" -o -name "*.key" 2>/dev/null | while read -r f; do
    if [ -f "$f" ]; then
        perms=$(stat -f "%Lp" "$f" 2>/dev/null || stat -c "%a" "$f" 2>/dev/null)
        if [ "${perms: -1}" != "0" ]; then

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/security-audit.sh (reported line 39)May include surrounding context.

sh
# 2. File permissions
log "▸ 2. FILE PERMISSIONS"
WORLD_READABLE=$(find "$WORKSPACE" -maxdepth 3 -name ".secrets" -o -name ".env" -o -name "*.key" 2>/dev/null | while read -r f; do
    if [ -f "$f" ]; then
        perms=$(stat -f "%Lp" "$f" 2>/dev/null || stat -c "%a" "$f" 2>/dev/null)
        if [ "${perms: -1}" != "0" ]; then

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/security-audit.sh (reported line 41)May include surrounding context.

sh
# 2. File permissions
log "▸ 2. FILE PERMISSIONS"
WORLD_READABLE=$(find "$WORKSPACE" -maxdepth 3 -name ".secrets" -o -name ".env" -o -name "*.key" 2>/dev/null | while read -r f; do
    if [ -f "$f" ]; then
        perms=$(stat -f "%Lp" "$f" 2>/dev/null || stat -c "%a" "$f" 2>/dev/null)
        if [ "${perms: -1}" != "0" ]; then

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/security-audit.sh (reported line 40)May include surrounding context.

sh
done)

if [ -n "$WORLD_READABLE" ]; then
    log "  ⚠️  World-readable sensitive files:"
    echo "$WORLD_READABLE" | while read -r f; do log "     $f"; done
    ISSUES=$((ISSUES + 1))
else

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script audits both the declared workspace and an unrelated hard-coded directory under $HOME/projects/bot-network, which expands its inspection scope beyond what the skill metadata describes. In an agent-maintenance context, this can disclose package/security posture for external projects and violates least-astonishment and least-privilege expectations.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The section header and inline comment describe 'Email Triage' and ask Reef whether any email is urgent, implying message-level assessment. In reality, the code only fetches the number of messages and sends Reef a prompt containing that count, so urgency cannot be determined from the actual emails.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.