Skill: marcusy2k/setup-validator (version 1.0.1)

--- name: setup-validator description: | Validate OpenClaw installation safety by checking for common security misconfigurations and setup issues. Use this skill during initial setup, periodic heartbeats, or whenever security validation is required. Checks include: excessive permissions, unsafe plugins, missing sandboxing, outdated dependencies, and more. Provides actionable warnings with fixes and clear documentation for resolving issues. --- # Setup Validator ## Overview This skill validates OpenClaw installations for security misconfigurations and setup issues. It runs during initial setup and periodically (e.g., via heartbeats or cron) to ensure ongoing safety. ## Checks The validator checks for the following issues: | Check | Description | Reference | |-------|-------------|-----------| | **Excessive Permissions** | Ensures OpenClaw and plugins have only necessary permissions. | [CHECKS.md](references/CHECKS.md) | | **Unsafe Plugins** | Identifies plugins from untrusted sources or with known vulnerabilities. | [CHECKS.md](references/CHECKS.md) | | **Missing Sandboxing** | Validates that sandboxing is properly configured. | [CHECKS.md](references/CHECKS.md) | | **Outdated Dependencies** | Checks for outdated or vulnerable dependencies. | [CHECKS.md](references/CHECKS.md) | See [CHECKS.md](references/CHECKS.md) for detailed descriptions of each check. ## Setup ### Make Scripts Executable Before using the scripts, ensure they have executable permissions: ```bash chmod +x ~/.openclaw/skills/setup-validator/scripts/*.py ``` ## Usage ### Run Validation Execute the validation script to check for misconfigurations: ```bash python scripts/validate_setup.py ``` ### Generate Actionable Warnings If issues are detected, generate actionable warnings with fixes: ```bash python scripts/generate_warnings.py ``` ### Example Output ```plaintext [WARNING] Excessive permissions detected for OpenClaw. - Fix: Run `chmod 750 ~/.openclaw` to restrict permissions. [WARNING] Unsafe plugin detected: example-plugin. - Fix: Remove the plugin with `openclaw plugin remove example-plugin`. ``` ## Documentation - [Detailed Checks](references/CHECKS.md) - [Example Fixes](references/EXAMPLE_FIXES.md) ## Periodic Validation To run this skill periodically (e.g., via cron or heartbeats), add the following to your cron jobs: ```bash 0 * * * * python ~/.openclaw/skills/setup-validator/scripts/validate_setup.py ```

path: references/CHECKS.md
content: # Setup Validator Checks

This document describes the checks performed by the **Setup Validator** skill. Each check includes a description, potential risks, and recommended fixes.

## 1. Excessive Permissions
### Description
Checks if OpenClaw or its plugins have excessive file or directory permissions.

### Risks
- Unauthorized access to sensitive files.
- Potential for privilege escalation attacks.

### Recommended Fix
- Restrict permissions to the minimum required:
  ```bash
  chmod 750 ~/.openclaw
  chmod 640 ~/.openclaw/config.yaml
  ```

## 2. Unsafe Plugins
### Description
Identifies plugins missing the required `openclaw.plugin.json` manifest or with invalid manifest structure.

### Risks
- Malicious plugins can execute arbitrary code.
- Plugins without manifests may not load correctly.
- Vulnerable plugins may expose sensitive data.

### Recommended Fix
- Validate plugin manifests:
  ```bash
  ~/.openclaw/skills/plugin-integration/scripts/validate-plugin.sh <plugin-dir>
  ```
- Remove unsafe plugins:
  ```bash
  openclaw plugins remove <plugin-name>
  ```
- Install plugins only from trusted sources.

## 3. Missing Sandboxing
### Description
Checks if sandboxing is configured for OpenClaw and its plugins.

### Risks
- Unrestricted access to system resources.
- Potential for sandbox escapes.

### Recommended Fix
- OpenClaw uses built-in sandboxing by default.
- Optional: Configure custom sandbox settings in `~/.openclaw/config.yaml`:
  ```yaml
  sandbox:
    enabled: true
    restrictions:
      network: true
      filesystem: true
  ```

## 4. Outdated Dependencies
### Description
Checks for outdated OpenClaw version using npm (OpenClaw is a Node.js package).

### Risks
- Known vulnerabilities in outdated versions.
- Compatibility issues with newer system components.
- Missing security patches.

### Recommended Fix
- Update OpenClaw:
  ```bash
  npm update -g openclaw
  ```
- Or use the OpenClaw CLI:
  ```bash
  openclaw update
  ```

## Example Output
```plaintext
📋 Checking Permissions...
  ✅ No issues found

📋 Checking Plugins...
  🚨 Unsafe Plugin: Plugin 'example-plugin' lacks an openclaw.plugin.json manifest file.
     Fix: Remove the plugin with `openclaw plugins remove example-plugin` or add a valid manifest.

📋 Checking Sandboxing...
  ℹ️ Sandboxing Info: No explicit sandbox configuration found. OpenClaw uses built-in sandboxing by default.

📋 Checking Dependencies...
  🚨 Outdated Dependencies: OpenClaw version 1.0.0 is outdated (latest: 1.2.0).
     Fix: Update OpenClaw with `npm update -g openclaw`.

============================================================
🚨 2 issue(s) detected
```

path: references/EXAMPLE_FIXES.md
content: # Example Fixes for Common Issues

This document provides example fixes for common security misconfigurations detected by the **Setup Validator** skill.

## 1. Excessive Permissions
### Issue
OpenClaw or its plugins have excessive file or directory permissions.

### Example Fix
Restrict permissions to the minimum required:
```bash
chmod 750 ~/.openclaw
chmod 640 ~/.openclaw/config.yaml
```

## 2. Unsafe Plugins
### Issue
A plugin is missing the required `openclaw.plugin.json` manifest or has invalid manifest structure.

### Example Fix
Validate the plugin:
```bash
~/.openclaw/skills/plugin-integration/scripts/validate-plugin.sh ~/.openclaw/plugins/example-plugin
```

Remove an unsafe plugin:
```bash
openclaw plugins remove example-plugin
```

## 3. Missing Sandboxing
### Issue
Sandboxing is not configured for OpenClaw or its plugins.

### Example Fix
OpenClaw uses built-in sandboxing by default. For custom configuration, edit `~/.openclaw/config.yaml`:
```yaml
sandbox:
  enabled: true
  restrictions:
    network: true
    filesystem: true
```

## 4. Outdated Dependencies
### Issue
OpenClaw version is outdated.

### Example Fix
Update OpenClaw (it's a Node.js package, use npm):
```bash
npm update -g openclaw
```

Or use the OpenClaw CLI:
```bash
openclaw update
```

## 5. Plugin Source Validation
### Issue
A plugin is installed from a source that is not verified.

### Example Fix
Reinstall the plugin from a trusted source:
```bash
openclaw plugins remove example-plugin
openclaw plugins install example-plugin --source trusted-repo
```

## 6. Configuration File Integrity
### Issue
The OpenClaw configuration file has incorrect or unsafe settings.

### Example Fix
Reset the configuration file to default:
```bash
openclaw config reset
```
Then reconfigure any custom settings manually.

path: scripts/generate_warnings.py
content: #!/usr/bin/env python3
"""
Generate Actionable Warnings

This script generates actionable warnings for issues detected by the Setup Validator.
It reads the output of `validate_setup.py` and formats it for user-friendly display.
"""

import json
import sys
from pathlib import Path


def generate_warnings(issues):
    """Generate actionable warnings from detected issues."""
    if not issues:
        print("✅ No issues detected. Setup is secure!")
        return
    
    print("🚨 Actionable Warnings:")
    for issue in issues:
        print(f"\n[WARNING] {issue['check']}")
        print(f"- {issue['description']}")
        print(f"- Fix: {issue['fix']}")


def main():
    """Main function."""
    # Example: Read issues from stdin or file
    if len(sys.argv) > 1:
        with open(sys.argv[1], "r") as f:
            issues = json.load(f)
    else:
        # Mock data for demonstration
        issues = [
            {
                "check": "Excessive Permissions",
                "description": "OpenClaw directory has excessive permissions: 777.",
                "fix": "Run `chmod 750 ~/.openclaw` to restrict permissions."
            },
            {
                "check": "Unsafe Plugin",
                "description": "Plugin 'example-plugin' lacks a manifest file.",
                "fix": "Remove the plugin with `openclaw plugin remove example-plugin`."
            }
        ]
    
    generate_warnings(issues)


if __name__ == "__main__":
    main()

path: scripts/validate_setup.py
content: #!/usr/bin/env python3
"""
Setup Validator Script

This script checks for common security misconfigurations and setup issues in OpenClaw.
It validates permissions, plugin safety, sandboxing, and dependency versions.
"""

import os
import subprocess
import sys
import json
from pathlib import Path

# Constants
OPENCLAW_DIR = os.path.expanduser("~/.openclaw")
CONFIG_FILE = os.path.join(OPENCLAW_DIR, "config.yaml")
PLUGIN_DIR = os.path.join(OPENCLAW_DIR, "plugins")


def check_permissions():
    """Check for excessive permissions on OpenClaw directories and files."""
    issues = []
    
    # Check OpenClaw directory
    if os.path.exists(OPENCLAW_DIR):
        openclaw_mode = os.stat(OPENCLAW_DIR).st_mode
        if openclaw_mode & 0o022:  # World-writable
            issues.append({
                "check": "Excessive Permissions",
                "description": f"OpenClaw directory has excessive permissions: {oct(openclaw_mode)}.",
                "fix": "Run `chmod 750 ~/.openclaw` to restrict permissions."
            })
    
    # Check config file
    if os.path.exists(CONFIG_FILE):
        config_mode = os.stat(CONFIG_FILE).st_mode
        if config_mode & 0o022:  # World-writable
            issues.append({
                "check": "Excessive Permissions",
                "description": f"Config file has excessive permissions: {oct(config_mode)}.",
                "fix": "Run `chmod 640 ~/.openclaw/config.yaml` to restrict permissions."
            })
    
    return issues


def check_plugins():
    """Check for unsafe plugins using the correct OpenClaw plugin manifest."""
    issues = []
    
    if not os.path.exists(PLUGIN_DIR):
        return issues
    
    # OpenClaw plugins use openclaw.plugin.json, not manifest.yaml or manifest.json
    for plugin in os.listdir(PLUGIN_DIR):
        plugin_path = os.path.join(PLUGIN_DIR, plugin)
        if os.path.isdir(plugin_path):
            manifest_path = os.path.join(plugin_path, "openclaw.plugin.json")
            if not os.path.exists(manifest_path):
                issues.append({
                    "check": "Unsafe Plugin",
                    "description": f"Plugin '{plugin}' lacks an openclaw.plugin.json manifest file.",
                    "fix": f"Remove the plugin with `openclaw plugins remove {plugin}` or add a valid manifest."
                })
            else:
                # Validate manifest is valid JSON
                try:
                    with open(manifest_path, 'r') as f:
                        manifest = json.load(f)
                    # Check for required fields
                    required = ['name', 'version']
                    missing = [f for f in required if f not in manifest]
                    if missing:
                        issues.append({
                            "check": "Invalid Plugin Manifest",
                            "description": f"Plugin '{plugin}' manifest missing required fields: {missing}",
                            "fix": f"Add missing fields to {manifest_path}"
                        })
                except json.JSONDecodeError as e:
                    issues.append({
                        "check": "Invalid Plugin Manifest",
                        "description": f"Plugin '{plugin}' has invalid JSON in manifest: {e}",
                        "fix": f"Fix the JSON syntax in {manifest_path}"
                    })
    
    return issues


def check_sandboxing():
    """Check if sandboxing is properly configured."""
    issues = []
    
    # Check for sandbox config in OpenClaw config
    # OpenClaw uses config.yaml or config.json
    config_yaml = os.path.join(OPENCLAW_DIR, "config.yaml")
    config_json = os.path.join(OPENCLAW_DIR, "config.json")
    
    if not os.path.exists(config_yaml) and not os.path.exists(config_json):
        issues.append({
            "check": "Missing Configuration",
            "description": "No OpenClaw config file found.",
            "fix": "Run `openclaw config init` to create a default configuration."
        })
        return issues
    
    # Check if sandbox settings exist (YAML or JSON)
    # Note: OpenClaw may not have explicit sandbox config - this is informational
    sandbox_configured = False
    
    if os.path.exists(config_yaml):
        try:
            import yaml
            with open(config_yaml, 'r') as f:
                config = yaml.safe_load(f) or {}
            if 'sandbox' in config or 'security' in config:
                sandbox_configured = True
        except:
            pass
    
    if not sandbox_configured and os.path.exists(config_json):
        try:
            with open(config_json, 'r') as f:
                config = json.load(f)
            if 'sandbox' in config or 'security' in config:
                sandbox_configured = True
        except:
            pass
    
    # This is informational, not an error - OpenClaw has built-in sandboxing
    if not sandbox_configured:
        issues.append({
            "check": "Sandboxing Info",
            "description": "No explicit sandbox configuration found. OpenClaw uses built-in sandboxing by default.",
            "fix": "Optional: Configure custom sandbox settings in config.yaml if needed."
        })
    
    return issues


def check_dependencies():
    """Check for outdated dependencies using npm (OpenClaw is a Node package)."""
    issues = []
    
    # OpenClaw is distributed via npm, not pip
    try:
        result = subprocess.run(
            ["npm", "list", "-g", "openclaw", "--json"],
            capture_output=True,
            text=True,
            timeout=10
        )
        if result.returncode == 0:
            data = json.loads(result.stdout)
            if data.get('dependencies', {}).get('openclaw'):
                version = data['dependencies']['openclaw'].get('version', 'unknown')
                # Check against latest
                latest_result = subprocess.run(
                    ["npm", "view", "openclaw", "version"],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                if latest_result.returncode == 0:
                    latest_version = latest_result.stdout.strip()
                    if version != latest_version:
                        issues.append({
                            "check": "Outdated Dependencies",
                            "description": f"OpenClaw version {version} is outdated (latest: {latest_version}).",
                            "fix": "Update OpenClaw with `npm update -g openclaw`."
                        })
    except subprocess.TimeoutExpired:
        issues.append({
            "check": "Dependency Check Timeout",
            "description": "Failed to check OpenClaw version (timeout).",
            "fix": "Ensure npm is available and run `npm list -g openclaw` manually."
        })
    except json.JSONDecodeError:
        issues.append({
            "check": "Dependency Check Error",
            "description": "Failed to parse npm output.",
            "fix": "Run `npm list -g openclaw` to check version manually."
        })
    except FileNotFoundError:
        # npm not found - check if openclaw command exists
        try:
            result = subprocess.run(
                ["openclaw", "--version"],
                capture_output=True,
                text=True,
                timeout=5
            )
            if result.returncode == 0:
                version = result.stdout.strip()
                issues.append({
                    "check": "Version Check",
                    "description": f"OpenClaw {version} is installed (npm not available for version check).",
                    "fix": "Install npm for full version checking, or use `openclaw update` to check for updates."
                })
        except:
            issues.append({
                "check": "Dependency Check Unavailable",
                "description": "Neither npm nor openclaw command found.",
                "fix": "Ensure OpenClaw is installed correctly."
            })
    
    return issues


def main():
    """Run all checks and print results."""
    checks = [
        ("Permissions", check_permissions),
        ("Plugins", check_plugins),
        ("Sandboxing", check_sandboxing),
        ("Dependencies", check_dependencies),
    ]
    
    all_issues = []
    for name, check_func in checks:
        print(f"\n📋 Checking {name}...")
        issues = check_func()
        all_issues.extend(issues)
        if issues:
            for issue in issues:
                severity = "⚠️ " if "Info" in issue.get("check", "") else "🚨"
                print(f"  {severity} {issue['check']}: {issue['description']}")
        else:
            print(f"  ✅ No issues found")
    
    print("\n" + "="*60)
    if not all_issues:
        print("✅ All checks passed! Setup is secure.")
        return 0
    
    # Filter actual errors from informational items
    errors = [i for i in all_issues if "Info" not in i.get("check", "")]
    
    if errors:
        print(f"🚨 {len(errors)} issue(s) detected:")
        for issue in errors:
            print(f"\n[{issue['check']}]")
            print(f"  {issue['description']}")
            print(f"  Fix: {issue['fix']}")
        return 1
    else:
        print(f"ℹ️ {len(all_issues)} informational item(s):")
        for issue in all_issues:
            print(f"  - {issue['check']}: {issue['description']}")
        return 0


if __name__ == "__main__":
    sys.exit(main())

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal:  | SkillSpector: suspicious (MEDIUM)