openclaw-scan 0.1.1

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](https://gitlab.com/pyratzlabs/software/Openclaw_Security_Tooling_CLI/badges/main/pipeline.svg)](https://gitlab.com/pyratzlabs/software/Openclaw_Security_Tooling_CLI/-/pipelines)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![crates.io](https://img.shields.io/crates/v/openclaw-scan.svg)](https://crates.io/crates/openclaw-scan)

`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

```bash
brew tap victorbinetruypic/ocls
brew install ocls
```

### Cargo

```bash
cargo install openclaw-scan
```

### Pre-built binary

Download the binary for your platform from the
[Releases page](https://gitlab.com/pyratzlabs/software/Openclaw_Security_Tooling_CLI/-/releases),
then:

```bash
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)

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

---

## Quick start

```bash
# 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:

```yaml
# 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

```bash
ocls --json
```

```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

```bash
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](CONTRIBUTING.md) for details.

---

## Contributing

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

- **Issues:** <https://gitlab.com/pyratzlabs/software/Openclaw_Security_Tooling_CLI/-/issues>
- **Contributing guide:** [CONTRIBUTING.md]CONTRIBUTING.md

---

## License

MIT — see [LICENSE](LICENSE).