Back to skill

Security audit

Fortress Agent Suite

Security checks for vulnerabilities and agentic risk

Overview

This is a high-privilege self-healing skill that discloses some risk, but it runs persistent root-level automation and can change system, Git, gateway, memory, and installed-skill state with weak user control.

Install only in a fully trusted, isolated OpenClaw environment after reviewing every scheduled job and script. Do not use it on shared systems or production hosts unless you are comfortable with root-level recurring execution, automatic configuration rollback, gateway restarts, Git commits, outbound Telegram notifications, and automatic installation of other skills. Before use, remove auto-skill installation and cron self-repair, replace shell-based commands, add an uninstall path, and keep backups outside any Git repository.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
Findings (8)

T06 · System Persistence

Error
Location
scripts/self-healing/workspace_watchdog.py:13
Finding

Root-Level Scheduled Persistence with Automatic Cron Repair

Content
View full analysis
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/self-healing/self_improver.py:43
Finding

Autonomous Installation of Mutable Remote Skills Without Payload Verification

Content
View full analysis
&1").read() if 'error' in result.lower() or 'failed' in result.lower(): log(f"Install failed {slug}: {result[:200]}", level='error') return False, result return True, result ``` ```python skill = fetch_skill(slug) if not skill: review.append((slug, 'Fetch fail')) continue safe, note = scan_content(skill.get('readme', skill.get('description', ''))) if not safe: review.append((slug, note)) continue github_url = skill.get('repo_url') or skill.get('github') or skill.get('source') gh = github_info(github_url) stars = gh.get('stars', 0) if stars and stars < MIN_GITHUB_STARS: review.append((slug, f'Low stars {stars}')) continue success, _ = install_skill(slug) ``` ### Technical Analysis The self-improver retrieves mutable metadata from ClawHub and then invokes `openclaw skills install` without pinning a version, commit, digest, or signature. Its security check only scans the remote README or description for a short list of strings. It does not inspect the package that is actually installed, executable files, Skill instructions, dependencies, or tra ...[truncated 1706 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/self-healing/self_improver.py:112
Finding

Root Command Injection Through Unvalidated Skill Slug

Content
View full analysis
&1").read() if 'error' in result.lower() or 'failed' in result.lower(): log(f"Install failed {slug}: {result[:200]}", level='error') return False, result return True, result ``` ```python for entry in candidates: slug = entry.get('slug') reason = entry.get('reason', 'No reason provided') if not slug or already_installed(slug): continue skill = fetch_skill(slug) ... success, _ = install_skill(slug) ``` The candidate data is loaded without validation: ```python def load_candidates(): ensure_candidates() with CANDIDATES_FILE.open() as f: return json.load(f) ``` ### Technical Analysis The candidate `slug` is read from JSON and interpolated directly into a string passed to `os.popen`. `os.popen` invokes a command shell, so metacharacters such as semicolons, command substitutions, pipes, redirections, and newlines are interpreted as shell syntax. URL quoting in `fetch_skill` does not sanitize the original `slug` later passed to the shell. The `already_installed` path check also does not enforce a safe identifier grammar. The project documentation explicitly describes root-level operation. Therefore, injection into this shell command is expected to execute with root privileges when the self-improver is run in the intended deployment context. ### Attack Path 1. An attacker obtains write access to `/root/.openclaw/scripts/self-healing/candidates.json`, or influences a process that writes candidate entries. 2. The attacker sets `slug` to a value containing shell syntax, such as a nominal identifier followed by a command separator and an arbitrary command. 3. The candidate r ...[truncated 784 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/self-healing/health_check.py:3
Finding

Telegram Configuration Enables Shell Injection and Exposes Bot Credentials in Process Arguments

Content
View full analysis
/dev/null") ``` The self-improver repeats the same pattern: ```python token = config.get('BOT_TOKEN') chat_id = config.get('CHAT_ID') if token and chat_id: os.system(f"curl -s 'https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}&text={urllib.parse.quote_plus(msg)}' > /dev/null") ``` ### Technical Analysis `BOT_TOKEN` and `CHAT_ID` are read from a configuration file and inserted into a single-quoted shell command. Neither value is validated or shell-escaped. A single quote in either value can terminate the URL literal and introduce arbitrary shell syntax. Additionally, placing the Telegram bot token directly in the `curl` command-line URL may expose it through process inspection while the command is running. Depending on host auditing and shell configuration, the URL may also enter execution or monitoring logs. The message body is URL-encoded, reducing injection through the current hardcoded messages, but this does not protect the token or chat ID fields. ### Attack Path 1. An attacker or compromised process modifies `/root/.openclaw/telegram_config`. 2. A crafted `BOT_TOKEN` or `CHAT_ID` contains a quote followed by shell syntax. 3. A gat ...[truncated 711 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Error
Location
scripts/self-healing/self_improver.py:99
Finding

Candidate-Controlled Text Is Written into Persistent Agent Memory

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/self-healing/backup.py:2
Finding

Sensitive OpenClaw Backups Can Be Automatically Added to Git History

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/self-healing/health_check.py:15
Finding

Any Gateway Status Error Triggers Unverified Configuration Rollback and Restart

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/self-healing/system_watchdog.py:3
Finding

Root Watchdog Deletes Logs and Modifies Kernel Cache State

Content
View full analysis
90: os.system('sync; echo 3 > /proc/sys/vm/drop_caches') ``` ### Technical Analysis The watchdog performs destructive and root-only actions in response to coarse global thresholds. Low root-filesystem space deletes all matching OpenClaw logs older than seven days without archiving them, checking whether they are needed for audit or incident response, or confirming how much space will be recovered. High swap utilization causes a system-wide cache drop through `/proc/sys/vm/drop_caches`. Dropping page cache, dentries, and inodes is not a general remedy for swap pressure and can degrade performance by forcing subsequent disk reads. This operation requires elevated privileges and affects the whole host rather than only OpenClaw. The fixed shell commands do not currently contain attacker-controlled interpolation, so direct command injection is not established. The issue is unnecessary privilege and destructive scope relative to monitoring. ### Attack Path 1. The scheduled watchdog runs every 30 minutes as configured. 2. Disk space falls below 500 MB, either naturally or because another process consumes storage. 3. The watchdog permanently deletes qualifying OpenClaw logs, potentially removing forensic evidence. 4. Alternatively, swap use exceeds 90%. 5. The watchdog writes `3` to `/proc/sys/vm/drop_caches`, affecting caching across the entire host. 6. Repeated threshold conditions cause repeated system-wide interventions ...[truncated 378 chars]
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (42)

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
92% confidence
Finding

This constructs a shell command with secrets and untrusted configuration values interpolated directly into it, then executes it with os.system(). Even though the message is URL-encoded, BOT_TOKEN and CHAT_ID come from a local file and are not shell-escaped, so a malicious or tampered config could trigger command injection; the command line may also expose the bot token to local process inspection.

Content

Scanner excerpt · scripts/self-healing/health_check.py (reported line 13)May include surrounding context.

python
cfg[k.strip()] = v.strip()
    token, chat_id = cfg.get('BOT_TOKEN'), cfg.get('CHAT_ID')
    if token and chat_id:
        os.system(f"curl -s 'https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}&text={urllib.parse.quote_plus(msg)}' > /dev/null")

def check():
    try:

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/model_manager/manager.py (reported line 21)May include surrounding context.

python
latest = backups[0]
    shutil.copy2(latest / 'openclaw.json', CONFIG)
    print(f"Restored from {latest}")
    os.system('openclaw gateway restart')

if __name__ == "__main__": run_restore()

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/self-healing/restore.py (reported line 12)May include surrounding context.

python
latest = backups[0]
    shutil.copy2(latest / 'openclaw.json', CONFIG)
    print(f"Restored from {latest}")
    os.system('openclaw gateway restart')

if __name__ == "__main__": run_restore()

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This script autonomously fetches metadata from external services, evaluates skills with a trivial keyword filter, and installs them automatically. That creates a remote supply-chain pathway where a malicious or compromised skill source can cause unreviewed code or instructions to be added to the system, especially since the safety screening is easily bypassed.

Content

No source excerpt is available for this finding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The code builds a shell command with untrusted values from the local Telegram config file and executes it via os.system. Even though the message text is URL-encoded, BOT_TOKEN and CHAT_ID are not shell-escaped, so a maliciously modified config file could inject arbitrary shell syntax and achieve command execution; additionally, it silently exfiltrates status data to an external service.

Content

Scanner excerpt · scripts/self-healing/self_improver.py (reported line 96)May include surrounding context.

python
token = config.get('BOT_TOKEN')
    chat_id = config.get('CHAT_ID')
    if token and chat_id:
        os.system(f"curl -s 'https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}&text={urllib.parse.quote_plus(msg)}' > /dev/null")


def append_memory(message):

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code automatically installs a skill by running an external command without any user warning, confirmation, or review step. In this context that is especially dangerous because installation is triggered by network-fetched candidate data and only guarded by simplistic checks, making unauthorized capability expansion likely.

Content

No source excerpt is available for this finding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The installer shells out with os.popen using a slug value that ultimately comes from a JSON candidates file and network-driven workflow. If an attacker can influence the slug or candidate source, they can inject shell metacharacters and execute arbitrary commands; beyond injection, this code autonomously installs remote skills without approval, expanding compromise risk.

Content

Scanner excerpt · scripts/self-healing/self_improver.py (reported line 114)May include surrounding context.

python
def install_skill(slug):
    log(f"Installing {slug}")
    result = os.popen(f"openclaw skills install {slug} 2>&1").read()
    if 'error' in result.lower() or 'failed' in result.lower():
        log(f"Install failed {slug}: {result[:200]}", level='error')
        return False, result

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This code invokes a shell via os.system() to delete log files automatically when disk space is low. Although the command string is static and not directly user-controlled, using a shell for destructive filesystem operations is risky because it bypasses safer APIs, depends on shell semantics, and can delete data without validation or auditing; if run with elevated privileges, mistakes or path manipulation around the target directory can cause broader data loss.

Content

Scanner excerpt · scripts/self-healing/system_watchdog.py (reported line 7)May include surrounding context.

python
# Disk space check (thấp hơn 500MB thì dọn log)
    total, used, free = shutil.disk_usage("/")
    if free < 500 * 1024 * 1024:
        os.system('find /root/.openclaw/logs -name "*.log" -mtime +7 -delete')

    # Memory check (nếu swap đầy thì dọn rác)
    if psutil.swap_memory().percent > 90:

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

This code executes a privileged shell command that writes to /proc/sys/vm/drop_caches, forcibly dropping kernel caches whenever swap usage exceeds a threshold. That is a high-risk operational action because it can degrade performance, interfere with normal system behavior, and requires elevated privileges; using os.system() also adds unnecessary shell exposure and makes the action harder to control safely.

Content

Scanner excerpt · scripts/self-healing/system_watchdog.py (reported line 11)May include surrounding context.

python
# Memory check (nếu swap đầy thì dọn rác)
    if psutil.swap_memory().percent > 90:
        os.system('sync; echo 3 > /proc/sys/vm/drop_caches')

if __name__ == "__main__": check_system()

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Automatically dropping system caches without warning or approval is a dangerous self-healing action because it changes global kernel memory behavior and may harm performance or destabilize workloads. In this watchdog context, the action is triggered unattended under resource pressure, increasing the chance of repeated disruptive behavior at the worst possible time.

Content

No source excerpt is available for this finding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This is the same unsafe shell-based auto-commit behavior identified earlier: it executes a constructed shell command and modifies the repository without consent. In a workspace-monitoring skill, silently committing all changes can hide tampering, capture secrets into version control, and alter the user's project state.

Content

Scanner excerpt · scripts/self-healing/workspace_watchdog.py (reported line 11)May include surrounding context.

python
status = subprocess.check_output(['git', '-C', str(WORKSPACE), 'status', '--porcelain']).decode()
        if status:
            # If there are uncommitted changes, auto-commit them (backup mode) / Nếu có thay đổi chưa commit, tự động commit (backup kiểu git)
            os.system(f"git -C {WORKSPACE} add . && git -C {WORKSPACE} commit -m 'Auto-backup: {os.popen('date').read().strip()}'")

    # Kiểm tra crontab
    cron = subprocess.check_output(['crontab', '-l']).decode()

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script modifies crontab entries to maintain recurring execution of local scripts, which is a broad persistence capability unrelated to normal one-shot skill operation. In this context, persistence is especially dangerous because the skill has no disclosed justification for installing scheduled tasks and can continue executing after the user stops interacting with it.

Content

No source excerpt is available for this finding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

This code silently modifies the user's crontab to ensure periodic execution of additional scripts, which is a persistence mechanism. Establishing scheduled execution without user consent is dangerous in a skill context because it survives beyond the original run and can repeatedly execute arbitrary code every 30 minutes.

Content

Scanner excerpt · scripts/self-healing/workspace_watchdog.py (reported line 18)May include surrounding context.

python
required = ["backup.py", "health_check.py", "system_watchdog.py"]
    for r in required:
        if r not in cron:
            os.system(f"crontab -l | {{ cat; echo '*/30 * * * * /root/.openclaw/.venv/bin/python /root/.openclaw/scripts/self-healing/{r}'; }} | crontab -")

if __name__ == "__main__": check_integrity()

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
96% confidence
Finding

The YARA match is credible because the code exhibits a classic persistence pattern: appending recurring cron jobs that launch local scripts. Even without an overt payload in this file, persistence in an undisclosed self-healing script is strongly suspicious and materially increases the chance of long-lived unauthorized code execution.

Content

Scanner excerpt · scripts/self-healing/workspace_watchdog.py (reported line 18)May include surrounding context.

python
động commit (backup kiểu git)
            os.system(f"git -C {WORKSPACE} add . && git -C {WORKSPACE} commit -m 'Auto-backup: {os.popen('date').read().strip()}'")

    # Kiểm tra crontab
    cron = subprocess.check_output(['crontab', '-l']).decode()
    required = ["backup.py", "health_check.py", "system_watchdog.py"]
    for r in required:
        if r not in cron:
            os.system(f"crontab -l | {{ cat; echo '*/30 * * * * /root/.openclaw/.venv/bin/python /root/.openclaw/scripts/self-healing/{r}'; }} | crontab -")

if __name__ == "__main__": check_integrity()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The installation guide instructs users to copy a crontab entry into the system scheduler, creating persistence and ongoing execution, but it does not explain what will run, how often it runs, or the operational and security implications. In the context of an agent skill, undocumented persistence is risky because it can continuously execute code outside normal user awareness and expand the blast radius if the skill is malicious or compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script modifies a root-owned configuration file and immediately restarts a gateway service without any prompt, dry-run, or rollback path. In an agent or automation context, this can cause unauthorized configuration changes, service disruption, or redirection of model traffic to a newly configured provider without meaningful operator awareness.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from pathlib.Path.read_text (line 9, file read) → pathlib.Path.write_text (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/model_manager/manager.py (reported line 20)May include surrounding context.

python
"baseUrl": "https://openrouter.ai/api/v1",
        "models": [{"id": model_id, "name": model_name}]
    }
    CONFIG.write_text(json.dumps(data, indent=2))
    os.system('openclaw gateway restart')
    print(f"Added {model_name} to 9Router.")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code performs filesystem writes and copies potentially sensitive local data from /root/.openclaw, including the main config and agent directory, into a backup location. While it prints the destination afterward, there is no prior warning, confirmation, or explanatory docstring/comment disclosing that sensitive configuration data will be duplicated.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The health-check reads local Telegram credentials and sends outbound notifications to an external service without clear necessity or user consent. In this context, that expands the trust boundary, creates a covert-ish exfiltration path for operational state, and is more concerning because the skill also performs self-healing actions automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Credential-backed outbound messaging occurs silently and without any user-facing disclosure or approval flow. That is dangerous because it can leak system status and establish unauthorized communications using stored credentials, especially in an agent skill where users may not expect hidden external notifications.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

This code transmits data to api.telegram.org using locally stored credentials, creating an external communication channel from a privileged health-check component. In skill context, undisclosed external transmission is more dangerous because it can leak service status and support unauthorized monitoring or abuse if the configuration is tampered with.

Content

Scanner excerpt · scripts/self-healing/health_check.py (reported line 13)May include surrounding context.

python
cfg[k.strip()] = v.strip()
    token, chat_id = cfg.get('BOT_TOKEN'), cfg.get('CHAT_ID')
    if token and chat_id:
        os.system(f"curl -s 'https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}&text={urllib.parse.quote_plus(msg)}' > /dev/null")

def check():
    try:

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/self-healing/health_check.py (reported line 17)May include surrounding context.

python
def check():
    try:
        subprocess.check_call(['openclaw', 'gateway', 'status'], timeout=5)
    except:
        msg = "Meo meo! Gateway is down. Đào is auto-restoring/restarting now!"
        send_telegram(msg)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script blindly copies the newest backup's openclaw.json over the active configuration without validation, integrity checking, backup provenance checks, or operator confirmation. If an attacker can place or modify a backup directory, they could cause restoration of a malicious configuration and the script will immediately apply it by restarting the gateway.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

No manifest is available to justify capabilities, so only clearly extra operational actions should be flagged. After restoring a backup config file, the script invokes a system-level command to restart the gateway, which is a broader administrative capability than simple file restoration and is not justified by any stated purpose.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/self-healing/self_improver.py (reported line 26)May include surrounding context.

python
]

SKILL_API = 'https://clawhub.ai/api/skills/{slug}'
GITHUB_API = 'https://api.github.com/repos/{owner}/{repo}'

COUNTER = 0

Static analysis

No suspicious patterns detected.