Back to skill

Security audit

openclawselfguard

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed OpenClaw vulnerability monitor, but it installs an enabled recurring agent job and its setup script has unsafe input handling, so it needs review before use.

Install only if you are comfortable with a daily persistent OpenClaw scheduled agent task. Review or disable setup_cron.sh first, avoid passing an untrusted delivery channel argument, and prefer an opt-in schedule with clear uninstall steps and pinned dependencies.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T06 · System Persistence

Error
Location
scripts/setup_cron.sh:8
Finding

Persistent Daily Agent Task Installed in OpenClaw Configuration

Content
View full analysis
"$OC_JOBS_FILE" ``` ### Technical Analysis The setup script modifies the persistent OpenClaw job configuration and registers an enabled task with a daily cron schedule. The task uses an `agentTurn` payload that instructs an agent to execute `check_vulns.py`. The task survives completion of the setup process and continues activating in future sessions. It references the script at its existing Skill installation path instead of copying a reviewed, immutable version into a protected execution location. Consequently, subsequent replacement or modification of that script changes the code executed by the already-installed task. Although the scheduled monitoring behavior is disclosed in the documentation, it still constitutes cross-session system persistence under the specified risk classification. ### Attack Path 1. A user installs the Skill and runs `scripts/setup_cron.sh`. 2. The script creates or modifies `~/.openclaw/cron/jobs.json`. 3. An enabled daily job is inserted into the persi ...[truncated 950 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup_cron.sh:31
Finding

Python Source Injection Through the Delivery Channel Argument

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/check_vulns.py:65
Finding

Incorrect Version-Range Evaluation Can Miss Vulnerable Installations

Content
View full analysis
tuple: """Check if version is affected by any of the ranges""" if not version or version == "unknown": return False, None for aff in affected_ranges: range_str = aff.get("range", "") fixed = aff.get("fixed", "") # Simple version comparison # e.g., ">= 1.0.0 < 1.5.0" means affected if 1.0.0 <= version < 1.5.0 if "<" in range_str and ">" in range_str: # Complex range, try to parse try: parts = range_str.split() for i, part in enumerate(parts): if part in [">=", "<=", ">", "<", "="]: op = part ver = parts[i + 1] if i + 1 < len(parts) else "" # Simplified check if op == ">=": if version < ver: return True, f"Affected by: {range_str}, Fix: {fixed}" except Exception: pass return False, None ``` ### Technical Analysis The function does not implement the range semantics described by its own comment. First, versions are compared as ordinary strings: ```python version < ver ``` Lexicographic ordering is not semantic-version ordering. For example, a version component containing two digits may sort before a smaller one-digit component when compared as text. Second, the logic handles only the `>=` operator. Operators such as `<`, `<=`, `>`, and `=` are recognized but never evaluated. Therefore, an upper boundary is not enforced. Third, the implemented lower-bound condition is reversed. For a range such as `>= 1.0.0 < 1.5.0`, a version below `1. ...[truncated 1368 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
references/requirements.txt:1
Finding

Unpinned and Unused Third-Party Dependencies Increase Supply-Chain Exposure

Content
View full analysis
=2.28.0 beautifulsoup4>=4.12.0 lxml>=4.9.0 ``` ### Technical Analysis Each requirement specifies only a minimum version. A future installation may therefore resolve to any later release available from the configured Python package index, including a release that was not reviewed or tested with this Skill. The requirements file also does not include cryptographic hashes, so package integrity is delegated entirely to the package index and transport configuration. This prevents reproducible dependency resolution. The audited Python scripts import `requests`, but no use of `beautifulsoup4` or `lxml` was found. Unused dependencies unnecessarily increase the package set that must be trusted and maintained. No evidence was found that these package names are typosquatted or currently malicious. The risk arises from avoidable, unbounded supply-chain exposure rather than a confirmed malicious package. ### Attack Path 1. A user or deployment process installs dependencies from `requirements.txt`. 2. The resolver selects the newest versions satisfying the lower bounds. 3. A future compromised, malicious, or incompatible release can be selected without a change to the Skill repository. 4. Package installation or later import executes or loads code from that unreviewed release. 5. The dependency code runs with the privileges of the installation or Skill process. ### Impact Assessment A compromised dependency can execute code under the installing or runtime user's account, access process-visible credentials and files, make network requests, or modify user configuration. The practical scope depends on how dependencies are installed. Installation as an ordinary user limits access to that user. Installation through a privileged system package process could expand the im ...[truncated 100 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly advertises automatic cron-job installation during setup, which creates persistence and modifies the user's scheduled tasks without any clear upfront warning, confirmation, or opt-in. Even if the stated purpose is security monitoring, silently establishing recurring execution increases risk because it normalizes background persistence and could be abused for repeated network access or future unauthorized actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation states that a daily cron job is installed automatically during skill setup, but it does not clearly warn that this creates persistence or alters system configuration. This is dangerous in skill ecosystems because users may invoke a seemingly simple security check while unintentionally authorizing long-lived background execution.

Content

No source excerpt is available for this finding.

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

python
cmd = ["python3", script_path] + list(args)
    
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This Python file contains user-facing natural-language strings entirely in Chinese for the generated vulnerability report, while the script offers no option to select language or opt in to this locale. That is a natural-language policy concern because it imposes a specific language on all users without documented justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring says the script fetches GitHub Security Advisories and checks for OpenClaw-related vulnerabilities, which implies a scoped, OpenClaw-focused behavior. However, the main flow at L137-L143 calls get_recent_advisories(), which retrieves advisories from seven ecosystems without filtering for OpenClaw, so the documentation materially overstates the code's specificity.

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

python
from datetime import datetime, timedelta
from typing import List, Dict, Optional

GITHUB_GHSA_API = "https://api.github.com/advisories"


def fetch_github_advisories(ecosystem: str = "npm", severity: str = None) -> List[Dict]:

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

python
"""Get the installed OpenClaw version"""
    try:
        # Try openclaw --version
        result = subprocess.run(
            ["openclaw", "--version"],
            capture_output=True,
            text=True,

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

python
"""Get the installed OpenClaw version"""
    try:
        # Try openclaw --version
        result = subprocess.run(
            ["openclaw", "--version"],
            capture_output=True,
            text=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This shell script contains natural-language strings that force a specific language/locale for the created cron job, such as the Chinese job name and later Chinese execution message. The policy allows locale constraints only when user choice or clear justification is provided, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The payload instructs the agent in Chinese and specifies a Chinese success response, which enforces a language choice on downstream behavior. Because the file does not offer a language option or justify a region-specific requirement, this is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

Hardcoding the cron schedule to run at 06:00 Beijing time without presenting it as user-configurable is a weaker but real safety issue because it imposes an unexplained execution policy and may trigger the task at unexpected local times. In combination with automatic installation, this reduces user awareness and control over when recurring networked activity occurs.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is specified with a lower bound only (requests>=2.28.0), which makes builds non-reproducible and allows future vulnerable or breaking releases to be installed without review. This is a real supply-chain hygiene weakness, especially because requests has multiple historical advisories and the exact resolved version cannot be verified from the manifest alone.

Content

Scanner excerpt · references/requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.28.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The manifest references requests without pinning an exact version, and requests has multiple known advisories across its release history. Because the resolved version is unknown, consumers of this skill could install an affected version, making the dependency status unverifiable and increasing supply-chain uncertainty.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

beautifulsoup4 is also unpinned, so installations may resolve to different versions over time, reducing reproducibility and increasing supply-chain exposure. While this is not direct code execution by itself, it creates uncertainty about what package version is actually deployed and whether it contains known flaws or incompatibilities.

Content

Scanner excerpt · references/requirements.txt (reported line 2)May include surrounding context.

text
requests>=2.28.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

lxml is unpinned despite having a history of security advisories, so the manifest does not guarantee installation of a safe version. This creates avoidable supply-chain risk and makes it impossible to verify from the file whether the deployed version is affected by known parser or sanitizer vulnerabilities.

Content

Scanner excerpt · references/requirements.txt (reported line 3)May include surrounding context.

text
requests>=2.28.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

Unverifiable Dependency: lxml has 14 known advisory(ies) (CVE-2021-43818 (lxml's HTML Cleaner allows crafted and SVG embedded scripts to pass through); CVE-2014-3146 (lxml Cross-site Scripting Via Control Characters); CVE-2021-28957 (lxml vulnerable to Cross-Site Scripting ) +11 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The manifest leaves lxml unpinned even though lxml has numerous historical security issues, including parser and sanitization-related vulnerabilities. If downstream users install a vulnerable release, attacker-controlled content processed by the library could increase the risk of XSS, parsing abuse, or related input-handling flaws in any code that uses it.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The comment at L063 says 'Create new job (no hard-coded channel)', but when CHANNEL is provided, L059-L061 and L080-L081 inject that channel value directly into the generated job JSON. This is a documentation-to-code contradiction about whether channel configuration is fixed into the job definition.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.