Back to skill

Security audit

ClawGears

Security checks for vulnerabilities and agentic risk

Overview

This OpenClaw security audit skill is mostly purpose-aligned, but it needs review because it performs sensitive local and network checks and has verified bugs that can miss or truncate important security findings.

Install only if you are comfortable with a macOS/OpenClaw security tool reading local configuration, permission, log, and process data. Do not run the IP leak check unless you accept sharing your public IP with external services and saving it locally. Treat generated reports as potentially incomplete until the listener-detection and set -e control-flow bugs are fixed, and approve interactive fixes one by one after reviewing the scripts.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate-report.sh:65
Finding
Gateway exposure report always misses publicly bound listeners<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-report.sh:65-69` **Vulnerability Type**: Incorrect security-state detection **Risk Level**: High ### Complete Code Snippet ```bash local gateway_bind=$(lsof -i :18789 2>/dev/null | grep -c "LISTEN" || true) if echo "$gateway_bind" | grep -q "0.0.0.0"; then result="FAIL" details="Gateway is bound to 0.0.0.0 (exposed to network)" fi ``` ### Technical Analysis The `grep -c "LISTEN"` command discards the actual `lsof` listener records and returns only a numeric count. The subsequent test searches that integer for the string `0.0.0.0`, which can never succeed. As a result, the report generator leaves `result` set to `PASS` even when OpenClaw is listening on all network interfaces. The implementation also does not account for wildcard IPv6 listeners such as `[::]`, which can expose the service beyond loopback. ### Attack Path 1. OpenClaw is intentionally or accidentally configured to listen on `0.0.0.0:18789` or another wildcard address. 2. The user runs `generate-report.sh`. 3. `lsof` finds the publicly accessible listener. 4. `grep -c` replaces the listener details with a numeric value such as `1`. 5. The test for `0.0.0.0` fails. 6. The generated report incorrectly records the network-exposure check as passing. 7. The user may leave the exposed service running based on the false assurance. 8. A remote party able to reach the host can attempt to access or attack the exposed OpenClaw gateway. ### Impact Assessment This flaw does not directly grant additional local privileges. Its security impact is a critical false negative: an internet- or LAN-accessible gateway may remain undetected. Depending on gateway authentication and capabilities, exposure could permit unauthorized interaction with the AI assistant, misuse of connected services, access to data available to the gateway, or consumption of associated API resources. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions Preserve and analyze the complete listener output rather than reducing it to a count: ```bash local gateway_bind gateway_bind=$(lsof -nP -iTCP:18789 -sTCP:LISTEN 2>/dev/null || true) if [ -z "$gateway_bind" ]; then result="SKIP" details="Gateway is not listening on port 18789" elif echo "$gateway_bind" | grep -Eq '(\*:18789|0\.0\.0\.0:18789|\[::\]:18789)'; then result="FAIL" details="Gateway is listening on a wildcard network address" elif echo "$gateway_bind" | grep -Eq '(127\.0\.0\.1:18789|\[::1\]:18789)'; then result="PASS" details="Gateway is restricted to loopback" else result="WARN" details="Gateway is listening on a non-loopback interface; manual review required" fi ``` Prefer a structured socket-inspection mechanism where available. Add automated tests covering no listener, IPv4 loopback, IPv6 loopback, IPv4 wildcard, IPv6 wildcard, and a specific non-loopback interface. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/quick-check.sh:414
Finding
Quick audit terminates when the first check reports a finding<![CDATA[ ## Vulnerability Details **File Location**: `scripts/quick-check.sh:11, 414-435` **Vulnerability Type**: Unsafe error-handling control flow **Risk Level**: High ### Complete Code Snippet ```bash set -e ``` ```bash check_network_exposure RESULT=$? if [ $RESULT -eq 1 ]; then ((ERRORS++)); fi check_token_security RESULT=$? if [ $RESULT -eq 1 ]; then ((ERRORS++)); fi if [ $RESULT -eq 2 ]; then ((WARNINGS++)); fi check_deny_commands RESULT=$? if [ $RESULT -eq 1 ]; then ((WARNINGS++)); fi check_fda_permission RESULT=$? if [ $RESULT -eq 1 ]; then ((WARNINGS++)); fi check_firewall RESULT=$? if [ $RESULT -eq 2 ]; then ((WARNINGS++)); fi ``` ### Technical Analysis The check functions deliberately return nonzero values to represent detected risks and warnings. However, global `set -e` causes Bash to terminate immediately when a directly invoked check returns a nonzero status. Execution stops before `RESULT=$?` can capture and classify the finding. Therefore, an exposed gateway or another early finding can prevent token, deny-list, Full Disk Access, and firewall checks from running. The intended summary may also never be printed. ### Attack Path 1. An unsafe condition causes an early check to return `1` or `2`. 2. Because the function is invoked as a standalone command under `set -e`, Bash immediately exits. 3. The status-handling statements following that call are not reached. 4. Subsequent security checks and the final summary are skipped. 5. Additional insecure settings remain undisclosed to the user. An attacker does not need direct code execution to benefit from this behavior. Any existing or attacker-induced early misconfiguration can suppress later audit coverage. ### Impact Assessment No additional operating-system privileges are directly obtained. The scope is the integrity and completeness of the security audit. Multiple vulnerabilities may remain undetected, and users may receive incomplete remediation guidance at precisely the point wh ...[truncated 34 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Execute expected nonzero-returning checks inside conditional contexts: ```bash run_check() { local rc if "$@"; then rc=0 else rc=$? fi return "$rc" } if run_check check_network_exposure; then RESULT=0 else RESULT=$? fi ``` Alternatively, redesign each check to print a structured status while returning zero for successfully completed checks, reserving nonzero process status for internal execution errors. Avoid post-increment expressions under `set -e`; use forms such as: ```bash ERRORS=$((ERRORS + 1)) WARNINGS=$((WARNINGS + 1)) ``` Add regression tests proving that all five checks and the summary run when every preceding check reports a warning or failure. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ip-leak-check.sh:343
Finding
IP leak audit exits before saving or summarizing detected exposure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ip-leak-check.sh:11, 343-363` **Vulnerability Type**: Unsafe error-handling control flow **Risk Level**: High ### Complete Code Snippet ```bash set -e ``` ```bash if [ "$CHECK_ALL" = true ] || [ -n "$CHECK_IP" ]; then check_allegro_exposure "$CHECK_IP" RESULT=$? if [ $RESULT -ne 0 ]; then ((ERRORS++)) fi echo "" check_censys_exposure "$CHECK_IP" echo "" check_shodan_exposure "$CHECK_IP" echo "" fi if [ "$CHECK_ALL" = true ] || [ "$CHECK_PORTS" = true ]; then check_port_exposure RESULT=$? if [ $RESULT -ne 0 ]; then ((ERRORS++)) fi echo "" fi ``` ### Technical Analysis Both `check_allegro_exposure` and `check_port_exposure` return a nonzero status when they detect exposure. Because the script enables `set -e` and invokes these functions directly, the shell can exit before the result is assigned to `RESULT`. This prevents later checks, local result persistence, and the final incident-response summary from executing. A positive exposure result therefore produces less complete evidence and guidance than a clean result. ### Attack Path 1. The selected public IP is reported as exposed, or a checked local port is bound to a wildcard address. 2. The relevant function returns a nonzero status. 3. Bash exits due to `set -e`. 4. Remaining database or port checks are skipped. 5. `save_leak_check_result` may not run. 6. The final consolidated exposure summary and remediation instructions may not be displayed. ### Impact Assessment The flaw does not itself expose additional data or grant system privileges. It compromises availability and completeness of incident-detection output. Users may lose the audit record and fail to identify other exposed ports or services during a security incident. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions Wrap finding-producing functions in explicit conditionals: ```bash if check_allegro_exposure "$CHECK_IP"; then RESULT=0 else RESULT=$? ERRORS=$((ERRORS + 1)) fi ``` Apply the same pattern to `check_port_exposure`. Ensure that findings are represented separately from internal execution failures so that the script can continue collecting evidence. Use a cleanup or exit trap if saving the result is mandatory: ```bash save_on_exit() { save_leak_check_result "$CHECK_IP" "$ERRORS" } trap save_on_exit EXIT ``` Avoid saving twice during normal execution if a trap is used. Add tests for exposed-IP responses, unavailable remote services, exposed local ports, and combinations of multiple findings. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate-report.sh:319
Finding
Report generation can abort on the first status counter increment<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-report.sh:319-322, 358-362` **Vulnerability Type**: Bash arithmetic status mishandling **Risk Level**: Medium ### Complete Code Snippet ```bash case $status in PASS) ((pass_count++)); css_class="pass" ;; FAIL) ((fail_count++)); css_class="fail" ;; WARN) ((warn_count++)); css_class="warn" ;; SKIP) css_class="skip" ;; esac ``` The JSON path uses the same pattern: ```bash case $status in PASS) ((pass_count++)) ;; FAIL) ((fail_count++)) ;; WARN) ((warn_count++)) ;; SKIP) ((skip_count++)) ;; esac ``` The script globally enables: ```bash set -e ``` ### Technical Analysis In Bash, the exit status of `((expression))` is zero only when the resulting expression evaluates as nonzero. A post-increment such as `((pass_count++))` evaluates to the counter's previous value. When the counter initially equals zero, the first increment returns status `1`. Under `set -e`, that ordinary first increment can terminate the script. HTML or JSON generation may consequently stop after the first processed status, leaving the report absent, incomplete, or malformed. ### Attack Path 1. The user starts HTML or JSON report generation. 2. The first audit check returns `PASS`, `FAIL`, or `WARN`. 3. The corresponding counter is initially zero. 4. The post-increment expression evaluates to zero and returns status `1`. 5. `set -e` terminates the report generator. 6. Remaining checks and final report structure are not written. The JSON path has the same issue for `SKIP` because it also increments `skip_count` using post-increment. ### Impact Assessment No local or remote privileges are gained. The affected scope is report availability and integrity. Security findings can be omitted, HTML output can be truncated, and JSON output may never be completed, undermining the Skill's primary reporting functionality. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions Replace post-increments with operations that do not return a false status when incrementing from zero: ```bash case $status in PASS) pass_count=$((pass_count + 1)); css_class="pass" ;; FAIL) fail_count=$((fail_count + 1)); css_class="fail" ;; WARN) warn_count=$((warn_count + 1)); css_class="warn" ;; SKIP) skip_count=$((skip_count + 1)); css_class="skip" ;; esac ``` Prefix increment, such as `((++pass_count))`, is also possible, but explicit assignment is clearer in scripts using `set -e`. Generate reports through a temporary file and atomically rename them only after successful completion. Validate generated JSON with `python3 -m json.tool` and test report creation with each possible status appearing first. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/interactive-fix.sh:357
Finding
Declined or failed remediation action terminates the interactive workflow<![CDATA[ ## Vulnerability Details **File Location**: `scripts/interactive-fix.sh:11, 357-364` **Vulnerability Type**: Unsafe interactive control flow **Risk Level**: Medium ### Complete Code Snippet ```bash set -e ``` ```bash # Run each fix fix_gateway_binding if [ $? -eq 0 ]; then ((fixes_applied++)); else ((fixes_skipped++)); fi fix_token if [ $? -eq 0 ]; then ((fixes_applied++)); else ((fixes_skipped++)); fi fix_deny_commands if [ $? -eq 0 ]; then ((fixes_applied++)); else ((fixes_skipped++)); fi ``` Individual remediation functions return a failure status when the user declines consent: ```bash if ! ask_confirmation "This will change Gateway bind to 'loopback' (127.0.0.1 only)"; then print_info "Skipped" return 1 fi ``` ### Technical Analysis A user declining an action is an expected interactive outcome, but the functions encode it as return status `1`. Because each function is called directly under `set -e`, declining the first action terminates the script before the intended skip counter or subsequent fixes are reached. Actual remediation failures cause the same premature termination. In addition, the post-increment counters can themselves return status `1` when incrementing from zero. Consent is not bypassed, but the implementation does not uphold the advertised interactive workflow or reliably complete a user-selected remediation sequence. ### Attack Path 1. The user selects “Run All Fixes.” 2. The user approves the overall workflow but declines one individual change, or an individual fix encounters an error. 3. The fix function returns status `1`. 4. `set -e` terminates the entire script. 5. Remaining approved remediation actions are never offered or applied. 6. Security settings that the user intended to fix remain unchanged. ### Impact Assessment The flaw does not grant an attacker extra privileges and does not bypass user confirmation. Its impact is remediation availability and consistency. A partially completed sequence may ...[truncated 165 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Distinguish successful application, user cancellation, and actual failure. For example: ```bash # Return values: # 0 = applied # 2 = declined # 1 = operational failure if ! ask_confirmation "Apply this change?"; then print_info "Skipped" return 2 fi ``` Handle every invocation inside a conditional context: ```bash run_fix() { local rc if "$@"; then fixes_applied=$((fixes_applied + 1)) return 0 else rc=$? fi if [ "$rc" -eq 2 ]; then fixes_skipped=$((fixes_skipped + 1)) else fixes_failed=$((fixes_failed + 1)) fi return 0 } ``` Replace all post-increment expressions with arithmetic assignments. Continue the menu after declined actions, clearly report partial completion, and verify each applied configuration change before proceeding. Where multiple related changes are intended as one operation, consider transactional updates with rollback from the existing backup. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

Vague Triggers

Medium
Confidence
92% confidence
Finding
The example trigger "Run a security audit" is generic and overlaps with common phrasing a user might use in many contexts, without clearly limiting it to this specific skill. The README does not provide scope constraints or exclusion examples to distinguish when this skill should activate versus other audit-related tools.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README states that IP leak detection checks external services such as allegro.earth, Censys, and Shodan, but gives no notice that running the check may disclose the user's IP address and metadata to third parties. In the context of a privacy and security auditing skill, this omission is especially risky because users may assume the audit is entirely local.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README advertises 'Auto-fix capabilities' without warning that remediation actions may modify system configuration, permissions, or security settings. In a security-focused skill, users may trust fixes blindly, increasing the chance of unintended system changes or privilege-affecting actions without informed consent.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation conditions are broad enough to trigger on generic security-related requests, including multilingual keywords that are not unique to this tool. That can cause the agent to invoke a skill that performs sensitive local inspection and network lookups in situations where the user did not specifically request this OpenClaw-focused audit flow, increasing the chance of unnecessary data access or external IP disclosure.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The script is presented as a report generator, but it actively collects host security data including network listeners, TCC permissions, local config contents, log contents, workspace symlinks, and home-directory item counts. In an agent-skill context, undeclared local inspection expands the script's effective privileges and can expose sensitive environmental data to users or downstream systems through generated reports.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This section reads sensitive local sources such as ~/.openclaw/openclaw.json, TCC.db, process/network state, and gateway logs without any user-facing warning or consent flow. Even if intended for auditing, accessing security tokens, permission state, and logs can reveal secrets or privacy-sensitive host metadata that may later be embedded in generated reports.

File System Enumeration

Medium
Category
Data Exfiltration
Content
local details=""

    for dir in Documents Pictures Desktop; do
        local count=$(ls -la ~/$dir/ 2>/dev/null | grep -v "^total" | grep -v "^.localized$" | wc -l)
        if [ "$count" -gt 0 ]; then
            if [ "$result" = "PASS" ]; then
                result="WARN"
Confidence
94% confidence
Finding
The ls-based enumeration of ~/Documents, ~/Pictures, and ~/Desktop inspects local filesystem contents as part of a script marketed primarily as a report generator. In an agent skill, filesystem enumeration is sensitive because it reveals existence and volume of personal data and can be repurposed for profiling or targeting even without exfiltrating file contents.

Session Persistence

Medium
Category
Rogue Agent
Content
# Start new
    print_info "Starting Gateway..."
    nohup openclaw-gateway > /dev/null 2>&1 &
    sleep 3

    # Verify
Confidence
65% 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.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script automatically sends the user's network-identifying data to multiple third-party services (ipify, icanhazip, ifconfig.me, and later the Allegro endpoint) without obtaining explicit consent or providing a privacy warning first. In a security-audit tool, this is dangerous because it expands disclosure of sensitive metadata to external operators and may itself create an exposure trail while the user believes they are only performing a local check.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The script prints Censys and Shodan guidance in Chinese, even though the rest of the script is in English, and it does not offer any language selection or explain a required locale. This can violate language or locale policy when users have not opted into that language.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This shell script is a code file, so SQP-3 applies to its natural-language strings. Many important status messages, warnings, and remediation steps are presented only in Chinese while other parts are in English, which imposes a locale choice on users without opt-in or documented justification.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "   • 如果您经常外出使用公共网络,建议开启"
        echo "   • 如果 Mac 固定在安全内网环境,可以保持关闭"
        echo "   • 开启命令:"
        echo "     sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on"
    fi

    echo ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "   • 如果您经常外出使用公共网络,建议开启"
        echo "   • 如果 Mac 固定在安全内网环境,可以保持关闭"
        echo "   • 开启命令:"
        echo "     sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on"
    fi

    echo ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "   • 如果您经常外出使用公共网络,建议开启"
        echo "   • 如果 Mac 固定在安全内网环境,可以保持关闭"
        echo "   • 开启命令:"
        echo "     sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on"
    fi

    echo ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "   • 如果您经常外出使用公共网络,建议开启"
        echo "   • 如果 Mac 固定在安全内网环境,可以保持关闭"
        echo "   • 开启命令:"
        echo "     sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on"
    fi

    echo ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "   • 如果您经常外出使用公共网络,建议开启"
        echo "   • 如果 Mac 固定在安全内网环境,可以保持关闭"
        echo "   • 开启命令:"
        echo "     sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on"
    fi

    echo ""
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The grading labels are presented in Chinese ("必须 / 建议 / 可选 / 评估后决定") inside an otherwise English document, and no opt-in or language-selection behavior is described nearby. This can violate language/locale policy expectations because the skill imposes a specific language in part of its instructions without confirming user preference.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The script enumerates user home subdirectories (Documents, Pictures, Desktop) to infer iCloud-sync risk without clearly informing the user. Although it only counts items, this still inspects personal filesystem state and may disclose behavioral or privacy-sensitive information in environments where the user expects only report formatting.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The generated HTML sets lang="en", which imposes an English locale in output without any user opt-in or indication that the report is region-specific. The policy requires avoiding forced language or locale choices unless users can choose or the constraint is clearly justified.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The script persists the user's public IP and exposure assessment into a local history file without explicit notice or consent. While local storage is less severe than external exfiltration, it creates sensitive forensic residue that may be readable by other local users, included in backups, or later exposed through other tooling.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
This shell script includes multiple user-facing instructional strings in Chinese, such as the explanatory and recommendation text beginning at L060, while the rest of the interface is partly English. Because the script does not provide any locale selection or user opt-in, it imposes a specific language on users and can violate language/locale policy expectations.

Static analysis

No suspicious patterns detected.