Back to skill

Security audit

OpenClaw Security Audit

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate OpenClaw security audit skill, but it understates its write and network behaviors and its optional Git backup can push broad local state to a remote repository.

Review this skill before installing on sensitive machines. Run it as a normal user where possible, treat generated reports as sensitive, and leave SECURITY_AUDIT_ENABLE_GIT and SECURITY_AUDIT_ENABLE_TELEGRAM unset unless you have reviewed the exact remote, payload, and repository contents. The core audit behavior is recognizable, but the current documentation and optional backup/notification flows need clearer boundaries.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/openclaw_security_audit.py:345
Finding

Predictable Report Path Permits Information Disclosure and Symbolic-Link File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/openclaw_security_audit.py:17-19, 345-356
Vulnerability Type: Unsafe temporary-file handling
Risk Level: Medium

Vulnerable Code

python
REPORT_DIR = Path('/tmp/openclaw-security-reports')
DATE_STR = datetime.date.today().isoformat()
REPORT_FILE = REPORT_DIR / f'report-{DATE_STR}.txt'
python
def setup_report_dir() -> None:
    REPORT_DIR.mkdir(parents=True, exist_ok=True)


def write_report(content: str) -> None:
    with open(REPORT_FILE, 'w', encoding='utf-8') as f:
        f.write(content)


def append_report(content: str) -> None:
    with open(REPORT_FILE, 'a', encoding='utf-8') as f:
        f.write(content)

Technical Analysis

The script stores security reports under a globally predictable directory and filename in /tmp. It creates the directory with default permissions and exist_ok=True, without confirming that the directory is owned by the current user, is not a symbolic link, or has restrictive permissions.

The subsequent calls to open() follow symbolic links and do not use secure creation controls such as O_EXCL or O_NOFOLLOW. The report file's effective permissions also depend on the process umask; with a common umask of 022, it may be created as world-readable.

Reports can contain sensitive operational information, including listening ports, process details, cron entries, login records, file-change information, configuration permissions, and installed Skill sources. The risk increases substantially if the audit is run as root or another privileged account.

Attack Path

  1. A local attacker predicts the report directory and daily filename: /tmp/openclaw-security-reports/report-YYYY-MM-DD.txt.
  2. Before the victim runs the audit, the attacker creates the report directory with permissions that allow the victim to write into it.
  3. The attacker places a symbolic link at the expected report f ...[truncated 1153 chars]
Remediation
View remediation

Remediation Suggestions

  1. Store reports in a user-private state directory rather than a shared predictable /tmp location.
  2. If temporary storage is required, use tempfile.mkdtemp() or tempfile.NamedTemporaryFile() with a securely randomized name.
  3. Create the report directory with mode 0700 and verify its owner before every use.
  4. Create report files with mode 0600.
  5. Use low-level secure creation flags such as O_CREAT | O_EXCL | O_NOFOLLOW, followed by os.fdopen().
  6. Reject existing files, symbolic links, and directories not owned by the effective user.
  7. Write reports atomically to a securely created temporary file and rename them after successful completion.
  8. Warn users against running the audit as root unless a specific check requires elevated access.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/openclaw_security_audit.py:917
Finding

Opt-In Git Backup Stages and Pushes the Entire OpenClaw State Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/openclaw_security_audit.py:917-945
Vulnerability Type: Overbroad collection and external transmission of sensitive files
Risk Level: Medium

Vulnerable Code

python
def audit_disaster_recovery(result: AuditResult) -> None:
    append_report(f"\n{t('disaster_recovery_header')}")

    if not ENABLE_GIT_BACKUP:
        append_report(t('backup_disabled'))
        result.add_success(t('backup_disabled'))
        return

    git_dir = OC_STATE_DIR / '.git'

    if not git_dir.exists():
        result.add_warning(t('no_git_repo'))
        return

    backup_status = "unknown"

    try:
        os.chdir(OC_STATE_DIR)

        run_command(['git', 'add', '.'], check=False)

        code, stdout, _ = run_command([
            'git', 'diff', '--cached', '--quiet'
        ], check=False)

        if code == 0:
            backup_status = "skip"
            append_report(t('no_changes'))
        else:
            commit_msg = f"OpenClaw daily backup ({DATE_STR})" if not USE_ZH else f"OpenClaw Daily Backup ({DATE_STR})"
            run_command([
                'git', 'commit', '-m', commit_msg
            ], check=False)

            code, _, stderr = run_command([
                'git', 'push', 'origin', 'main'
            ], check=False)

Technical Analysis

The Git disaster-recovery feature is disabled by default and requires explicit activation through SECURITY_AUDIT_ENABLE_GIT. This reduces exposure, but the enabled implementation executes git add . from the root of OC_STATE_DIR and pushes the resulting commit to origin/main.

There is no file allowlist, sensitive-file denylist, secret scan, remote validation, staged-file review, or confirmation immediately before transmission. Consequently, every unignored file beneath the OpenClaw state directory may be committed and sent to the configured remote.

The state di ...[truncated 2166 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace git add . with an explicit allowlist of files required for disaster recovery.
  2. Exclude credentials, key material, .env files, device secrets, memory, reports, caches, logs, and other private workspace content by design rather than relying solely on .gitignore.
  3. Run a secret scanner against the staged diff before committing or pushing.
  4. Display the resolved remote URL and staged-file list, then require separate confirmation before the first push.
  5. Refuse unencrypted or unexpected remote destinations and document the trust requirements for the remote.
  6. Check return codes for git add and git commit; abort the push if either operation fails.
  7. Consider producing a locally encrypted backup archive containing only approved state instead of committing the complete state directory.
  8. Clearly document that enabling this feature transmits selected data to an external Git server and that deleted secrets may remain in repository history.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (27)

Tainted flow: 'req' from os.environ.get (line 988, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

This code sends audit summaries to Telegram, which is external network exfiltration of potentially sensitive host security information. Because the skill advertises itself as local-only/read-only and the summary may include security posture details, enabling this feature can leak operationally sensitive data off-host.

Content

Scanner excerpt · scripts/openclaw_security_audit.py (reported line 989)May include surrounding context.

python
}).encode()

        req = urllib.request.Request(url, data=data)
        with urllib.request.urlopen(req) as response:
            return response.getcode() == 200
    except Exception as e:
        append_report(f"\n{t('telegram_send_failed', str(e))}")

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documentation repeatedly describes the skill as read-only and local-only, but it also states that it writes reports/baselines and can perform Git push and Telegram notification when enabled. This mismatch is dangerous because operators may grant trust and elevated access based on inaccurate safety claims, while the skill actually has persistence and network exfiltration paths.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/openclaw_security_audit.py

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

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

Content

Scanner excerpt · scripts/openclaw_security_audit.py (reported line 543)May include surrounding context.

python
dirs_to_check = [
        OC_STATE_DIR,
        Path('/etc'),
        Path.home() / '.ssh',
        Path.home() / '.gnupg',
        Path('/usr/local/bin')
    ]

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

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

Content

Scanner excerpt · scripts/openclaw_security_audit.py (reported line 682)May include surrounding context.

python
dirs_to_check = [
        OC_STATE_DIR,
        Path('/etc'),
        Path.home() / '.ssh',
        Path.home() / '.gnupg',
        Path('/usr/local/bin')
    ]

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The manifest claims operations are read-only and local-only, but this function stages files, commits them, and pushes them to a remote Git repository. That mismatch can mislead operators into granting trust to a skill that can exfiltrate local state and modify repository history.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code transmits audit summaries to Telegram despite the manifest stating operations are local-only. In a high-privilege audit context, even summarized results can reveal system configuration, exposure status, and other sensitive intelligence useful to an attacker.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SECURITY.md (reported line 55)May include surrounding context.

md
| Transmission | All scans are **local-only** |
| External Communication | Only opt-in features (Git push, Telegram) - disabled by default |
| Report Storage | `/tmp/openclaw-security-reports/` only |
| Retention | Reports are not automatically deleted, user-managed |
| Privacy | No personal data is collected or transmitted |

## Security Guarantees

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises high-privilege auditing behavior and the documentation references shell commands, environment inspection, file access, reporting, and optional external communications, yet the manifest declares no explicit tool scope. In a high-privilege skill, missing permission boundaries is dangerous because it leaves effective capabilities implicit and harder to review, increasing the chance of overbroad execution or accidental misuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Claiming the skill is 'read-only and local-only' while documenting optional Git push and Telegram features creates a materially misleading security declaration. Even if opt-in, these features expand the trust boundary beyond the host and can move sensitive audit data off-system.

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

md
| OpenClaw Cron | Retrieves internal OpenClaw scheduled tasks |
| SSH Audit | Recent logins and failed SSH attempts |
| File Integrity | SHA256 hash and permission checks |
| Yellow Line Audit | Compares sudo logs with memory records |
| Disk Usage | Root partition usage and large files |
| Environment Variables | Scans Gateway process for sensitive vars |
| DLP Scan | Detects plaintext private keys/mnemonics (read-only) |

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

python
| OpenClaw Cron | Retrieves internal OpenClaw scheduled tasks |
| SSH Audit | Recent logins and failed SSH attempts |
| File Integrity | SHA256 hash and permission checks |
| Yellow Line Audit | Compares sudo logs with memory records |
| Disk Usage | Root partition usage and large files |
| Environment Variables | Scans Gateway process for sensitive vars |
| DLP Scan | Detects plaintext private keys/mnemonics (read-only) |

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

python
| OpenClaw Cron | Retrieves internal OpenClaw scheduled tasks |
| SSH Audit | Recent logins and failed SSH attempts |
| File Integrity | SHA256 hash and permission checks |
| Yellow Line Audit | Compares sudo logs with memory records |
| Disk Usage | Root partition usage and large files |
| Environment Variables | Scans Gateway process for sensitive vars |
| DLP Scan | Detects plaintext private keys/mnemonics (read-only) |

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

python
| OpenClaw Cron | Retrieves internal OpenClaw scheduled tasks |
| SSH Audit | Recent logins and failed SSH attempts |
| File Integrity | SHA256 hash and permission checks |
| Yellow Line Audit | Compares sudo logs with memory records |
| Disk Usage | Root partition usage and large files |
| Environment Variables | Scans Gateway process for sensitive vars |
| DLP Scan | Detects plaintext private keys/mnemonics (read-only) |

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The 'All scans are local-only' statement is contradicted by later documentation for Telegram notifications and Git push to remote destinations. Such contradictory assurances can cause reviewers or users to underestimate exfiltration risk, especially because the skill also scans for highly sensitive material like credentials and private keys.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill determines whether to use Chinese by inspecting LANG/LC_* and then globally sets USE_ZH, which changes all user-facing output automatically. This is a natural-language locale policy concern because the skill does not offer the user an explicit language choice or opt-in before switching languages.

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 · scripts/openclaw_security_audit.py (reported line 128)May include surrounding context.

python
'baseline_ok': '配置基线: 哈希校验通过且权限合规',
        'baseline_warning': '配置基线: 基线缺失/校验异常或权限不合规',
        'yellow_line_header': '黄线操作对比 (sudo logs vs memory)',
        'sudo_log': 'Sudo 日志: {}, Memory 日志: {}',
        'yellow_line_ok': '黄线审计: sudo记录={}, memory记录={}',
        'disk_usage_header': '磁盘使用率与最近大文件',
        'disk_usage': '磁盘使用: {}, 大文件 (>100M): {}',

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

python
'baseline_ok': '配置基线: 哈希校验通过且权限合规',
        'baseline_warning': '配置基线: 基线缺失/校验异常或权限不合规',
        'yellow_line_header': '黄线操作对比 (sudo logs vs memory)',
        'sudo_log': 'Sudo 日志: {}, Memory 日志: {}',
        'yellow_line_ok': '黄线审计: sudo记录={}, memory记录={}',
        'disk_usage_header': '磁盘使用率与最近大文件',
        'disk_usage': '磁盘使用: {}, 大文件 (>100M): {}',

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

python
timeout: int = 30
) -> Tuple[int, str, str]:
    try:
        result = subprocess.run(
            cmd,
            capture_output=capture,
            text=True,

Scope Creep

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script writes reports to /tmp despite the manifest declaring all operations are read-only. This is a trust-boundary violation because operators may rely on the read-only claim when deciding whether to run the skill on sensitive systems.

Content

No source excerpt is available for this finding.

Scope Creep

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The integrity audit creates and updates baseline files under the state directory, which directly contradicts the claimed read-only scope. On privileged systems, undocumented writes can alter evidence, create persistence artifacts, or simply break operator expectations around non-invasive auditing.

Content

No source excerpt is available for this finding.

Tainted flow: 'cur_hash' from os.environ.get (line 858, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/openclaw_security_audit.py (reported line 873)May include surrounding context.

python
except Exception:
                        pass

    with open(cur_hash, 'w') as f:
        for path, hash_val in sorted(current_hashes.items()):
            f.write(f"{hash_val}  {path}\n")

Tainted flow: 'cur_hash' from os.environ.get (line 858, credential/environment) → shutil.copy (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/openclaw_security_audit.py (reported line 904)May include surrounding context.

python
else:
            # first time generating baseline
            import shutil
            shutil.copy(cur_hash, base_hash)
            result.add_success(t('integrity_first'))
    else:
        result.add_success(t('integrity_no_files'))

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Automatic Git backup can transmit local data externally without a prominent warning at the moment of use. In a security audit skill that inspects sensitive directories and state, this weak consent model materially increases the risk of unintended disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Telegram notification sends audit data off-host without a strong user-facing warning at send time. Because this is a privileged audit tool, silent or lightly signaled outbound messaging can expose system status to third parties unexpectedly.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.