openclaw-scan 0.1.0

Security scanner for agentic AI framework installations (OpenClaw, Claude Code, and compatible)
Documentation

ocls — OpenClaw Security Scanner

Offline security scanner for agentic AI framework installations.

Pipeline License: MIT crates.io

ocls scans your OpenClaw, Claude Code, or any compatible agentic AI framework directory and produces an actionable security report — covering credential exposure, permission misconfigurations, unsafe hook scripts, insecure MCP endpoints, and data retention risks.

Works with all model backends: Claude, OpenAI, Mistral, xAI/Grok, OpenRouter, Google Gemini, and more. The threat surface is framework-level, not model-level. Nothing is sent anywhere — analysis runs entirely on your machine.


Features

  • 7 scanner categories — config, secrets, permissions, network, dependencies, hooks, data exposure
  • 100–0 score with letter grade (A–F) per category and overall
  • Rich terminal output with ANSI colour, score bars, and per-finding remediation
  • JSON output for CI pipelines, dashboards, and jq scripting
  • Parallel scanning via Rayon — fast even on large history files
  • Single static binary — no runtime, no dependencies
  • Auto-detects ~/.claude, ~/.openclaw, $OPENCLAW_HOME, or accepts an explicit path

Installation

Homebrew (macOS / Linux) — recommended

brew tap victorbinetruypic/ocls
brew install ocls

Cargo

cargo install openclaw-scan

Pre-built binary

Download the binary for your platform from the Releases page, then:

chmod +x ocls-*
sudo mv ocls-* /usr/local/bin/ocls
Platform Binary
Linux x86_64 (musl) ocls-linux-x86_64
Linux aarch64 (musl) ocls-linux-aarch64
macOS Apple Silicon ocls-macos-aarch64
macOS Intel ocls-macos-x86_64

From source (requires Rust ≥ 1.75)

git clone https://gitlab.com/pyratzlabs/software/Openclaw_Security_Tooling_CLI.git
cd Openclaw_Security_Tooling_CLI
cargo install --path .

Quick start

# Auto-detect your installation and scan it
ocls

# Scan a specific directory
ocls ~/.claude

# Scan multiple directories
ocls ~/.openclaw ~/projects/my-agent/.claude

# Show only HIGH and above
ocls --min-severity high

# Full detail: remediation steps + evidence for every finding
ocls -v

# Machine-readable JSON for scripting / CI
ocls --json | jq '.overall_score'

# Scan only the secrets category
ocls --category secrets

# Disable colour output (e.g. in scripts or CI logs)
ocls --no-color

Example output

╔════════════════════════════════════════════════════╗
║  ocls v0.1.0  ·  OpenClaw Security Scanner        ║
╚════════════════════════════════════════════════════╝

Scanning ~/.claude  [auto-detected · Claude Code]

FINDINGS ──────────────────────────────────────────────
● CRITICAL  [Secrets]       AWS key in history.jsonl:234
● HIGH      [Config]        Bash(*) allow rule in settings.json
● HIGH      [Permissions]   .credentials.json world-readable (644)
● MEDIUM    [Network]       HTTP MCP endpoint: http://api.example.com
● LOW       [Dependencies]  Plugin not updated in 90+ days

SUMMARY ───────────────────────────────────────────────

  Score  67 / 100   Grade: C

  Config        ████████░░  78    1 high   1 medium
  Secrets       ██████░░░░  55    1 critical
  Permissions   ███████░░░  70    1 high
  Network       ████████░░  82    1 medium
  Dependencies  █████████░  92    1 low
  Hooks         ██████████ 100    —
  Data          ████████░░  80    —

  5 findings  (1 critical · 2 high · 1 medium · 1 low)

Run `ocls -v` for remediation steps.
Run `ocls --json` for machine-readable output.

CLI reference

ocls [OPTIONS] [PATH]...

Arguments:
  [PATH]...  Path(s) to scan. Repeatable. Auto-detects if omitted.

Options:
  -j, --json                       Output machine-readable JSON
  -q, --quiet                      Suppress banner; findings only
  -v, --verbose                    Show remediation and evidence per finding
      --no-color                   Disable ANSI colour codes
      --category <CATEGORY>        Scan only one category
                                   [config|secrets|permissions|network|deps|hooks|history]
      --min-severity <SEVERITY>    Minimum severity to show  [default: low]
                                   [critical|high|medium|low|info]
      --ignore-path <GLOB>         Exclude path from scan (repeatable)
  -h, --help                       Print help
  -V, --version                    Print version

Exit codes

Code Meaning
0 No findings at or above --min-severity
1 One or more findings present
2 Scan error (path not found, permission denied, etc.)

Use exit code 1 in CI to fail a build when security issues are found:

# GitLab CI example
security-scan:
  script:
    - ocls --min-severity high --json > security-report.json
  artifacts:
    paths: [security-report.json]

Path auto-detection

If no path argument is given, ocls probes in this order and uses the first match:

  1. $OPENCLAW_HOME
  2. ~/.openclaw/
  3. ~/.claude/
  4. ~/.config/openclaw/
  5. ./ (if it contains a known framework marker file)

Scanner categories

Category What it checks
Config settings.json wildcard allow rules, dangerouslySkipPermissions, MCP alwaysAllow
Secrets AI provider keys (Anthropic, OpenAI, Mistral, xAI, OpenRouter, Gemini…), AWS/GitHub/GitLab tokens, private keys, JWTs, DB connection strings found in history, plans, debug files, and CLAUDE.md
Permissions File mode bits on credentials, history, settings, and backup directories
Network Unencrypted http:// MCP endpoints, bare IP addresses in server configs, OAuth misconfiguration
Dependencies Installed plugins vs. blocklist, tamper detection via stored hash, staleness (>90 days), unofficial sources
Hooks Shell injection via unquoted variables / backticks, --dangerously-skip-permissions, outbound curl/wget calls, world-writable hook scripts
Data Exposure history.jsonl > 10 MB, debug/ > 50 MB, backups older than 30 days, unrotated telemetry UUIDs

Secret evidence is always redacted in output (sk-ant-****, ghp_****, etc.) — the full value is never printed.


Scoring

Each finding deducts points from a 100-point baseline:

Severity Penalty
Critical −25 pts
High −12 pts
Medium −5 pts
Low −2 pts
Info 0 pts

Grades: A (90–100) · B (75–89) · C (60–74) · D (40–59) · F (<40)

Category sub-scores use the same formula applied independently per category.


JSON output format

ocls --json
{
  "version": "0.1.0",
  "scanned_at": "2025-03-03T10:30:00Z",
  "scanned_paths": ["/home/user/.claude"],
  "overall_score": 67,
  "overall_grade": "C",
  "total_critical": 1,
  "total_high": 2,
  "total_medium": 1,
  "total_low": 1,
  "total_info": 0,
  "categories": [ ... ],
  "findings": [
    {
      "severity": "critical",
      "category": "secret_detection",
      "title": "Anthropic API key in history.jsonl",
      "description": "A live Anthropic API key was found at line 42 of history.jsonl.",
      "path": "/home/user/.claude/history.jsonl",
      "line": 42,
      "evidence": "sk-ant-****",
      "remediation": "Rotate the key immediately at console.anthropic.com, then clear your history."
    }
  ]
}

Development

Running the tests

cargo test --all            # unit + integration tests
cargo clippy -- -D warnings # lint
cargo fmt --check           # formatting

Adding a new scanner rule

Each scanner lives in src/scanner/<name>.rs and implements the Scanner trait. Rules are unit-tested in the same file; integration tests go in tests/integration/. See CONTRIBUTING.md for details.


Contributing

Bug reports, rule suggestions, and pull requests are welcome.


License

MIT — see LICENSE.