Back to skill

Security audit

Clawhub Skill Infra Watchdog

Security checks for vulnerabilities and agentic risk

Overview

This monitoring skill mostly matches its stated purpose, but it asks for broad OpenClaw capabilities and its HTTPS/SSL checks are unsafe enough to give false health results.

Review before installing. Use it only if you are comfortable granting broad monitoring-related capabilities, and do not rely on its HTTPS or SSL-expiry results until certificate validation and expiry parsing are fixed. Prefer a version with narrower manifest permissions and explicit user control for any alerts or scheduled checks.

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

T09 · Insecure Skill Coding Practices

Error
Location
watchdog.py:171
Finding
TLS Certificate Validation Is Explicitly Disabled<![CDATA[ ## Vulnerability Details **File Location**: `watchdog.py:171-174` and `watchdog.py:261-265` **Vulnerability Type**: Improper certificate validation **Risk Level**: High ### Vulnerable Code HTTP monitoring disables certificate-chain and hostname verification: ```python ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE req = urllib.request.Request(target, method='HEAD') with urllib.request.urlopen(req, context=ctx, timeout=timeout) as resp: elapsed = (time.time() - start) * 1000 status_code = resp.status return ('up', elapsed, f'HTTP {status_code}') ``` The dedicated certificate monitor repeats the insecure configuration: ```python ctx = ssl_module.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl_module.CERT_NONE with socket.create_connection((host, 443), timeout=10) as sock: with ctx.wrap_socket(sock, server_hostname=host) as ssock: cert_der = ssock.getpeercert_der() import ssl as ssl_module cert = ssl_module.DER_cert_to_PEM_cert(cert_der) # Simple extraction import re match = re.search(r'notAfter=(.*?)[\r\n]', cert, re.DOTALL) if match: return ('up', 0, f'Certificate valid') ``` ### Technical Analysis Setting `check_hostname` to `False` and `verify_mode` to `ssl.CERT_NONE` disables the two principal controls used to authenticate a TLS server: 1. Validation of the certificate chain against trusted certificate authorities. 2. Verification that the certificate identity matches the requested hostname. Consequently, HTTPS monitoring accepts self-signed, expired, hostname-mismatched, and attacker-issued certificates. A successful TLS connection can therefore cause a monitored service to be reported as available even when the connection was intercepted. The certificate-expiry implementation is also unreliable. It calls `SSLSocket.getpeercert_der()`, which is not the standard Python API for obtaining ...[truncated 1421 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Preserve the secure defaults provided by `ssl.create_default_context()`: ```python ctx = ssl.create_default_context() ``` Remove both `ctx.check_hostname = False` and `ctx.verify_mode = ssl.CERT_NONE`. 2. Use the validated context for HTTPS requests and treat certificate-validation failures as a failed check. 3. Retrieve the peer certificate using the supported API: ```python cert_der = ssock.getpeercert(binary_form=True) ``` 4. Parse the certificate with a maintained X.509 implementation, such as `cryptography.x509`, rather than applying a regular expression to PEM data. 5. Compare the parsed `not_valid_after_utc` value with the configured warning threshold and distinguish valid, warning, expired, and validation-failure states. 6. Add automated tests for trusted certificates, self-signed certificates, expired certificates, hostname mismatches, and certificates nearing expiration. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
skill.json:14
Finding
Skill Manifest Requests Capabilities Beyond Implemented Requirements<![CDATA[ ## Vulnerability Details **File Location**: `skill.json:14-15` **Vulnerability Type**: Excessive tool permissions and violation of least privilege **Risk Level**: Medium ### Vulnerable Code ```json "openclaw": { "compatible": true, "minVersion": "1.0.0", "tools": ["message", "canvas", "exec", "cron"] } ``` ### Technical Analysis The manifest requests access to messaging, canvas, arbitrary execution, and scheduling tools. The reviewed Python implementation does not use the `message` or `canvas` capabilities. Its `cron-install` command only prints setup instructions and does not invoke a scheduling API: ```python def cmd_cron_install(args): """Install cron job for periodic checks.""" config = load_config() interval = config.get('check_interval_minutes', 5) print(f"✅ Cron job would run every {interval} minutes.") print(" To activate: set up in OpenClaw's cron system") print(f" Command: infra-watchdog check") ``` Although local subprocesses are used for fixed-argument Docker and resource checks, the manifest's broad capability set exceeds the functionality implemented in the package. Requesting unnecessary capabilities expands the consequences of a future code defect, compromised instruction flow, or malicious package update. The reviewed source does not demonstrate that these tools are currently abused, so this finding concerns excessive authorization and attack-surface exposure rather than confirmed execution through those tools. ### Attack Path 1. A user installs or enables the skill and grants the tool capabilities declared by its manifest. 2. The skill receives broader access than its implemented monitoring operations require. 3. A later compromised update, instruction-manipulation issue, or exploitable code path invokes an unnecessary capability. 4. Depending on host enforcement, the capability could be used to send messages, create scheduled activity, manipulate UI content, or execute commands outside the ...[truncated 699 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove capabilities that are not required by the current implementation, particularly `message`, `canvas`, and `cron`. 2. If the platform supports granular execution policies, replace broad `exec` access with narrowly scoped permission to invoke only the required binaries and argument patterns, such as: - `docker inspect <container-id>` - `df -h <mount-point>` - `free -b` 3. Add alerting or scheduling capabilities only when the corresponding functionality is implemented, reviewed, and explicitly enabled by the operator. 4. Require explicit user confirmation before enabling outbound messaging or persistent scheduling. 5. Document why each requested capability is necessary and add a release check that rejects unused permissions in the manifest. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

External Transmission

Medium
Category
Data Exfiltration
Content
infra-watchdog add-monitor \
  --type http \
  --name "Main API" \
  --url https://api.example.com/health \
  --expected-status 200 \
  --timeout 5
```
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def check_docker(self, container_id: str) -> Tuple[str, float, str]:
        """Check Docker container status. Returns (status, 0, details)."""
        try:
            result = subprocess.run(
                ['docker', 'inspect', container_id],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def check_disk(self, mount_point: str = '/') -> Tuple[str, float, str]:
        """Check disk usage. Returns (status, 0, details)."""
        try:
            result = subprocess.run(
                ['df', '-h', mount_point],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def check_memory(self) -> Tuple[str, float, str]:
        """Check memory usage. Returns (status, 0, details)."""
        try:
            result = subprocess.run(
                ['free', '-b'],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The SSL expiry check disables certificate verification and hostname checking, then reports only a generic 'Certificate valid' message without actually parsing and evaluating the certificate's expiration date. This can cause false assurance: expired, spoofed, or otherwise invalid certificates may be treated as healthy, undermining monitoring and delaying detection of certificate failures or MITM conditions.

Session Persistence

Medium
Category
Rogue Agent
Content
def cmd_cron_install(args):
    """Install cron job for periodic checks."""
    config = load_config()
    interval = config.get('check_interval_minutes', 5)
Confidence
80% 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

Low
Confidence
78% confidence
Finding
This code creates a persistent data directory in the user's home workspace, and later stores configuration and monitoring results in local files and a SQLite database. While some success messages are printed, there is no explicit disclosure that the skill persistently records monitor targets and check history on disk, which is relevant to user data handling.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The skill actively sends HTTP requests to user-specified targets and opens TCP connections to remote hosts as part of monitoring. Although this behavior is central to the skill's purpose, the code does not clearly warn users during setup or command execution that endpoint information and connection metadata will be transmitted to those remote systems.

Static analysis

No suspicious patterns detected.