Skill: laurentaia/ai-shield-audit (version 1.0.0)

--- name: openclaw-shield description: Security audit engine for OpenClaw configurations. Detects vulnerabilities, misconfigurations, secret leaks, and over-privileged agents. Use when the user asks about security, hardening, config review, or audit of their OpenClaw setup. metadata: {"openclaw":{"emoji":"🛡️","homepage":"https://github.com/autonomous-intelligence/openclaw-shield"}} --- # OpenClaw Shield — Security Audit Audit any OpenClaw config for security vulnerabilities, misconfigurations, and best-practice violations. Produces a structured JSON report with risk scores, findings, and remediation steps. ## When to Use - User asks to check/audit/review their OpenClaw security - User wants to harden their config before deploying - User is setting up a new OpenClaw instance - User asks about secret leakage or API key exposure in their config - Before publishing or sharing any config file ## Quick Audit (live config) ```bash node scripts/shield-audit.sh ``` Or directly: ```bash node SKILL_DIR/bin/shield.js audit ~/.openclaw/openclaw.json --summary ``` ## What It Checks (11 categories) 1. **Gateway Auth** — missing/weak auth, insecure UI settings 2. **Network Exposure** — bind address, Tailscale funnel, wildcard proxies 3. **Channel Security** — wildcard allowFrom, missing allowlists 4. **DM Policy** — open DM policy without pairing 5. **Subagent Permissions** — wildcard allowAgents, circular delegation chains, self-delegation 6. **Tool Permissions** — over-privileged agents with tools.profile: "full" 7. **Secret Leakage** — API keys, tokens, private keys in plaintext config 8. **Sandbox/Execution** — missing workspace isolation, no execution policies 9. **Plugin Config** — enabled plugins without channel config 10. **Heartbeat Exposure** — sensitive data in heartbeat prompts 11. **Remote Config** — unencrypted WebSocket, exposed remote URLs/tokens ## Usage ### Audit a config file ```bash node SKILL_DIR/bin/shield.js audit <config.json> node SKILL_DIR/bin/shield.js audit <config.json> --summary # human-readable ``` ### Audit from stdin ```bash cat config.json | node SKILL_DIR/bin/shield.js audit --stdin ``` ### Sanitize a config (strip secrets) ```bash node SKILL_DIR/bin/shield.js sanitize <config.json> ``` ### Programmatic use ```javascript const { auditConfig } = require('SKILL_DIR/src/audit'); const config = require('./openclaw.json'); const report = auditConfig(config); console.log(report.risk_level); // "CRITICAL" | "HIGH" | "MEDIUM" | "LOW" console.log(report.overall_score); // 0-100 console.log(report.vulnerabilities); // detailed findings ``` ## Output Returns JSON with: `risk_level`, `overall_score` (0-100), `vulnerabilities[]`, `vulnerability_count`, `best_practices_compliance`, `action_recommended`, `safe_to_deploy`, `audit_timestamp`. ## Workflow for Agent 1. Load the user's config: `cat ~/.openclaw/openclaw.json` 2. Run: `node SKILL_DIR/bin/shield.js audit ~/.openclaw/openclaw.json --summary` 3. Present findings to user with prioritized recommendations 4. Offer to sanitize before sharing: `node SKILL_DIR/bin/shield.js sanitize <file>`

path: README.md
content: # 🛡️ OpenClaw Shield

**Security audit engine for OpenClaw configurations.** Find vulnerabilities, misconfigurations, and secret leaks before they become breaches.

Built by [Autonomous Intelligence](https://autonomousintelligence.ai) — we run 9 agents in production. We know what breaks.

## Features

- **11 security check categories** covering auth, networking, channels, agents, secrets, and more
- **Structured JSON reports** with risk scores, severity levels, and remediation steps
- **Config sanitizer** to strip secrets before sharing
- **CLI tool** for quick audits
- **Zero dependencies** — pure Node.js, no npm install needed

## Quick Start

```bash
# Audit your live config
node bin/shield.js audit ~/.openclaw/openclaw.json --summary

# Get JSON report
node bin/shield.js audit ~/.openclaw/openclaw.json

# Strip secrets before sharing
node bin/shield.js sanitize ~/.openclaw/openclaw.json > safe-config.json
```

## Sample Output

```
╔══════════════════════════════════════════════════╗
║         🛡️  OpenClaw Shield Audit Report         ║
╚══════════════════════════════════════════════════╝

  Risk Level:    HIGH
  Score:         42/100
  Safe to Deploy: ❌ No
  Action:        REVIEW_AND_REMEDIATE

  Vulnerabilities: 12
    🔴 Critical: 2
    🟠 High:     3
    🟡 Medium:   4
    🔵 Low:      3
```

## Security Checks

| # | Category | What It Catches |
|---|----------|----------------|
| 1 | Gateway Auth | Missing auth token, insecure UI, weak tokens |
| 2 | Network Exposure | Non-loopback bind, Tailscale funnel, wildcard proxies |
| 3 | Channel Security | Wildcard allowFrom, missing allowlists |
| 4 | DM Policy | Open DM policy without pairing |
| 5 | Subagent Permissions | Wildcard allowAgents, circular chains, self-spawn |
| 6 | Tool Permissions | Over-privileged agents (full tool access) |
| 7 | Secret Leakage | API keys, tokens, private keys in plaintext |
| 8 | Sandbox/Execution | Missing workspace isolation, no exec policies |
| 9 | Plugin Config | Orphaned plugins, missing channel configs |
| 10 | Heartbeat Exposure | Sensitive data in heartbeat prompts |
| 11 | Remote Config | Unencrypted WebSocket, exposed remote tokens |

## JSON Report Schema

```json
{
  "risk_level": "CRITICAL|HIGH|MEDIUM|LOW",
  "overall_score": 0-100,
  "vulnerabilities": [{
    "category": "string",
    "severity": "critical|high|medium|low",
    "issue": "Description of the problem",
    "recommendation": "How to fix it",
    "auto_fix": { "path": "config.path", "value": "suggested_value" }
  }],
  "vulnerability_count": { "critical": 0, "high": 0, "medium": 0, "low": 0, "total": 0 },
  "best_practices_compliance": 0.0-1.0,
  "action_recommended": "BLOCK|REVIEW_AND_REMEDIATE|APPROVE",
  "safe_to_deploy": true|false,
  "audit_timestamp": "ISO8601",
  "engine_version": "1.0.0"
}
```

## Programmatic Usage

```javascript
const { auditConfig } = require('./src/audit');
const { sanitizeConfig } = require('./src/sanitize');

// Audit
const config = require('./my-openclaw.json');
const report = auditConfig(config);

if (!report.safe_to_deploy) {
  console.log(`${report.vulnerability_count.critical} critical issues found!`);
}

// Sanitize before sharing
const clean = sanitizeConfig(config);
```

## Pricing

- **Local audit:** Free (install the skill, run locally)
- **Premium remote audit:** $0.10/audit via ACP (deeper analysis + auto-fix patches)

## License

MIT — Autonomous Intelligence 2026


path: bin/shield.js
content: #!/usr/bin/env node
/**
 * OpenClaw Shield CLI
 * Usage:
 *   shield audit <config.json>          — run security audit
 *   shield audit --stdin                 — read config from stdin
 *   shield sanitize <config.json>        — strip secrets from config
 *   shield sanitize --stdin              — read from stdin
 *   shield audit --live                  — audit the running OpenClaw instance
 */

'use strict';

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const { auditConfig } = require('../src/audit');
const { sanitizeAndStringify } = require('../src/sanitize');

const args = process.argv.slice(2);
const command = args[0];

function usage() {
  console.log(`OpenClaw Shield v1.0.0 — Security Audit for OpenClaw Configs

Usage:
  shield audit <config.json>    Audit a config file
  shield audit --stdin          Audit config from stdin
  shield audit --live           Audit the running OpenClaw config
  shield sanitize <config.json> Strip secrets from config
  shield sanitize --stdin       Strip secrets from stdin
  shield --help                 Show this help

Options:
  --json          Output raw JSON (default for audit)
  --pretty        Pretty-print JSON output
  --summary       Human-readable summary instead of JSON

Examples:
  node bin/shield.js audit ~/.openclaw/openclaw.json
  openclaw config.get | node bin/shield.js audit --stdin
  node bin/shield.js audit --live --summary
`);
}

function loadConfig() {
  if (args.includes('--live')) {
    try {
      const raw = execSync('openclaw config.get', { encoding: 'utf-8', timeout: 10000 });
      return JSON.parse(raw);
    } catch (e) {
      // config.get may not be available, try reading the file directly
      const configPath = path.join(process.env.HOME || '/root', '.openclaw', 'openclaw.json');
      if (fs.existsSync(configPath)) {
        return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
      }
      console.error('Error: Could not load live config. Is OpenClaw running?');
      process.exit(1);
    }
  }

  if (args.includes('--stdin')) {
    const input = fs.readFileSync('/dev/stdin', 'utf-8');
    return JSON.parse(input);
  }

  const filePath = args.find(a => !a.startsWith('-'));
  if (filePath && filePath !== command) {
    return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
  }

  // Try second positional arg
  const fileArg = args[1];
  if (fileArg && !fileArg.startsWith('-')) {
    return JSON.parse(fs.readFileSync(fileArg, 'utf-8'));
  }

  console.error('Error: No config source specified. Use a file path, --stdin, or --live.');
  process.exit(1);
}

function formatSummary(report) {
  const lines = [];
  const icons = { critical: '🔴', high: '🟠', medium: '🟡', low: '🔵' };

  lines.push('');
  lines.push('╔══════════════════════════════════════════════════╗');
  lines.push('║         🛡️  OpenClaw Shield Audit Report         ║');
  lines.push('╚══════════════════════════════════════════════════╝');
  lines.push('');
  lines.push(`  Risk Level:    ${report.risk_level}`);
  lines.push(`  Score:         ${report.overall_score}/100`);
  lines.push(`  Safe to Deploy: ${report.safe_to_deploy ? '✅ Yes' : '❌ No'}`);
  lines.push(`  Action:        ${report.action_recommended}`);
  lines.push('');
  lines.push(`  Vulnerabilities: ${report.vulnerability_count.total}`);
  lines.push(`    🔴 Critical: ${report.vulnerability_count.critical}`);
  lines.push(`    🟠 High:     ${report.vulnerability_count.high}`);
  lines.push(`    🟡 Medium:   ${report.vulnerability_count.medium}`);
  lines.push(`    🔵 Low:      ${report.vulnerability_count.low}`);
  lines.push('');
  lines.push('─'.repeat(52));

  for (const v of report.vulnerabilities) {
    lines.push('');
    lines.push(`  ${icons[v.severity]} [${v.severity.toUpperCase()}] ${v.category}`);
    lines.push(`    Issue: ${v.issue}`);
    lines.push(`    Fix:   ${v.recommendation}`);
  }

  lines.push('');
  lines.push('─'.repeat(52));
  lines.push(`  Compliance: ${(report.best_practices_compliance * 100).toFixed(0)}%`);
  lines.push(`  Audit time: ${report.audit_timestamp}`);
  lines.push(`  Engine:     v${report.engine_version}`);
  lines.push('');

  return lines.join('\n');
}

// ── Main ──

if (!command || args.includes('--help') || args.includes('-h')) {
  usage();
  process.exit(0);
}

try {
  if (command === 'audit') {
    const config = loadConfig();
    const report = auditConfig(config);

    if (args.includes('--summary')) {
      console.log(formatSummary(report));
    } else {
      console.log(JSON.stringify(report, null, 2));
    }

    // Exit code based on risk
    process.exit(report.risk_level === 'CRITICAL' ? 2 : report.risk_level === 'HIGH' ? 1 : 0);

  } else if (command === 'sanitize') {
    const config = loadConfig();
    console.log(sanitizeAndStringify(config));

  } else {
    console.error(`Unknown command: ${command}. Use --help for usage.`);
    process.exit(1);
  }
} catch (e) {
  console.error(`Error: ${e.message}`);
  process.exit(1);
}


path: package.json
content: {
  "name": "openclaw-shield",
  "version": "1.0.0",
  "description": "Security audit engine for OpenClaw configurations — find vulnerabilities, misconfigs, and secret leaks before they become breaches.",
  "main": "src/audit.js",
  "bin": {
    "shield": "bin/shield.js"
  },
  "scripts": {
    "audit": "node bin/shield.js audit --live --summary",
    "audit:json": "node bin/shield.js audit --live",
    "test": "node bin/shield.js audit --live --summary"
  },
  "keywords": [
    "openclaw",
    "security",
    "audit",
    "config",
    "hardening"
  ],
  "author": "Autonomous Intelligence",
  "license": "MIT"
}


path: scripts/shield-audit.sh
content: #!/bin/bash
# Quick audit wrapper for OpenClaw Shield
# Usage: ./scripts/shield-audit.sh [config-path] [--summary|--json]

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SHIELD="$SCRIPT_DIR/../bin/shield.js"

CONFIG="${1:-$HOME/.openclaw/openclaw.json}"
FORMAT="${2:---summary}"

exec node "$SHIELD" audit "$CONFIG" "$FORMAT"


path: src/sanitize.js
content: #!/usr/bin/env node
/**
 * OpenClaw Shield — Config Sanitizer
 * Strips secrets from an OpenClaw config before external submission.
 */

'use strict';

const REDACTED = '[REDACTED]';

const SECRET_KEY_PATTERNS = [
  /key$/i, /token$/i, /secret$/i, /password$/i, /credential$/i, /private/i,
];

const SECRET_VALUE_PATTERNS = [
  /^sk-or-v1-[a-f0-9]+$/i,         // OpenRouter
  /^sk-[a-zA-Z0-9]+$/i,             // Generic API key
  /^\d+:[A-Za-z0-9_-]{35,}$/,       // Telegram bot token
  /^0x[a-fA-F0-9]{64}$/i,           // Private key
  /^xai-[a-zA-Z0-9]+$/i,            // xAI
  /^ghp_[a-zA-Z0-9]+$/i,            // GitHub
  /^gho_[a-zA-Z0-9]+$/i,            // GitHub OAuth
  /^glpat-[a-zA-Z0-9_-]+$/i,        // GitLab
  /^AKIA[0-9A-Z]{16}$/i,            // AWS
];

function sanitizeConfig(config) {
  return deepSanitize(JSON.parse(JSON.stringify(config)), []);
}

function deepSanitize(obj, path) {
  if (obj === null || obj === undefined) return obj;

  if (Array.isArray(obj)) {
    return obj.map((item, i) => deepSanitize(item, [...path, String(i)]));
  }

  if (typeof obj === 'object') {
    const result = {};
    for (const [key, val] of Object.entries(obj)) {
      result[key] = deepSanitize(val, [...path, key]);
    }
    return result;
  }

  if (typeof obj === 'string') {
    const currentKey = path[path.length - 1] || '';

    // Check if key name suggests a secret
    if (SECRET_KEY_PATTERNS.some(p => p.test(currentKey))) {
      return REDACTED;
    }

    // Check if value looks like a secret
    if (SECRET_VALUE_PATTERNS.some(p => p.test(obj))) {
      return REDACTED;
    }

    // Redact env sections aggressively
    if (path.includes('env') && obj.length > 20) {
      return REDACTED;
    }
  }

  return obj;
}

function sanitizeAndStringify(config, pretty = true) {
  const clean = sanitizeConfig(config);
  return pretty ? JSON.stringify(clean, null, 2) : JSON.stringify(clean);
}

module.exports = { sanitizeConfig, sanitizeAndStringify };


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