Skill: jimpang8/security-network-hardening (version 1.0.0)

--- name: security-network-hardening description: Audit and harden an OpenClaw host and its network exposure. Use for security checks, hardening, firewall setup, network exposure review, metrics endpoint restriction, OpenClaw gateway security fixes, or step-by-step remediation on a Linux host running OpenClaw. --- # Security + Network Hardening Audit first, then harden with explicit approval. Keep this file short; read the references when needed. ## Core rules - Start read-only unless the user explicitly asks for fixes. - Require confirmation before any state-changing action. - Preserve current management access; do not break SSH/RDP/VNC. - Prefer exact findings over generic advice. - After workspace edits, commit them. ## Read-only baseline Run: ```bash uname -a cat /etc/os-release id ss -ltnup 2>/dev/null || ss -ltnp 2>/dev/null openclaw security audit --deep openclaw update status openclaw status --deep ``` If firewall state matters, also run: ```bash ufw status verbose || true firewall-cmd --state 2>/dev/null || true nft list ruleset 2>/dev/null || true ``` ## Priorities Check for these first: 1. elevated wildcard access in `tools.elevated.allowFrom.*` 2. writable credentials directories 3. missing gateway auth rate limiting 4. broad or unclear listening ports 5. metrics endpoints exposed too widely 6. ineffective custom `gateway.nodes.denyCommands` 7. workspace skill symlink escapes ## Fix patterns Read these only when relevant: - UFW/firewall workflow: `references/ufw-playbook.md` - OpenClaw config fixes: `references/openclaw-fix-patterns.md` ## Artifact generation When the user wants generated files, create: - `firewall-rules.md` - `apply-firewall.sh` - `scripts/rollback-firewall.sh` - `scripts/verify-firewall.sh` ## Safe firewall order 1. Confirm allowed source subnet/IPs. 2. Add SSH rule first if SSH is in use. 3. Apply LAN-only and single-host rules. 4. Verify from expected clients. 5. Re-check `ufw status verbose` and `ss -ltnp`. ## Verification After fixes, verify with: ```bash openclaw security audit --deep openclaw gateway status python3 -m json.tool ~/.openclaw/openclaw.json >/dev/null sudo ufw status verbose ss -ltnp ``` Success means: - no critical audit findings - no warning audit findings when practical - gateway reachable - required ports reachable only from approved sources

path: references/openclaw-fix-patterns.md
content: # OpenClaw Fix Patterns

## Common findings and fixes

### Elevated wildcard access

Look for both global and agent-level settings in `~/.openclaw/openclaw.json`.

Bad:

```json
"allowFrom": {
  "<channel>": ["*"]
}
```

Safer:

```json
"allowFrom": {
  "<channel>": []
}
```

### Credentials directory too permissive

Restrict the credentials directory so only the owner can access it.

Recommended fix pattern:

```bash
chmod 700 <openclaw-credentials-dir>
```

### Missing gateway auth rate limiting

Recommended baseline:

```json
"auth": {
  "mode": "token",
  "token": "...",
  "rateLimit": {
    "maxAttempts": 10,
    "windowMs": 60000,
    "lockoutMs": 300000
  }
}
```

### Ineffective `gateway.nodes.denyCommands`

Do not invent command IDs. If audit flags custom deny entries as ineffective and they are not needed, remove the custom denylist instead of replacing it with guesses.

### Workspace skill symlink escape

If a workspace skill resolves outside the workspace root, replace the symlink with a real in-workspace copy.

## Verification commands

```bash
openclaw security audit --deep
openclaw gateway status
python3 -m json.tool ~/.openclaw/openclaw.json >/dev/null
openclaw status --deep
```

## Baseline pattern

A good baseline usually includes:
- remove elevated wildcard access from interactive channels
- set the OpenClaw credentials directory to `700`
- add `gateway.auth.rateLimit`
- remove ineffective custom `gateway.nodes.denyCommands`
- replace workspace skill symlinks that escape the workspace root


path: references/ufw-playbook.md
content: # UFW Playbook

## Baseline policy

Use this on Ubuntu hosts that should accept only explicitly approved inbound traffic.

```bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
```

## LAN-only service examples

Use the host's actual LAN subnet and only the ports the user confirms are needed.

```bash
sudo ufw allow from <lan-cidr> to any port 22 proto tcp comment 'SSH from LAN'
sudo ufw allow from <lan-cidr> to any port <dashboard-port> proto tcp comment 'Dashboard from LAN'
sudo ufw allow from <lan-cidr> to any port <rdp-port> proto tcp comment 'RDP from LAN'
sudo ufw allow from <lan-cidr> to any port <vnc-port> proto tcp comment 'VNC from LAN'
```

## Single-host metrics restriction

Prefer a single-host rule for metrics when only one scraper needs access.

```bash
sudo ufw allow from <metrics-scraper-ip> to any port <metrics-port> proto tcp comment 'Metrics scraper'
```

## Safe apply sequence

1. Confirm the management path in use now.
2. Add SSH allow rule first if SSH is in use.
3. Apply LAN-only and single-host rules.
4. Enable UFW.
5. Verify reachability from expected clients.

## Review rules

```bash
sudo ufw status numbered
sudo ufw status verbose
```

## Remove rules

```bash
sudo ufw delete <number>
```

## Backup current rules

```bash
sudo ufw status numbered > ~/ufw-rules-$(date +%F).txt
sudo iptables-save > ~/iptables-$(date +%F).save
```

## Notes

- Do not expose remote desktop or VNC ports directly to the public internet.
- Do not expose `/metrics` broadly.
- OpenClaw WhatsApp/Discord integrations usually do not need new inbound firewall rules; outbound access is typically enough.


path: scripts/rollback-firewall.sh
content: #!/usr/bin/env bash
set -euo pipefail

STAMP="${1:-}"

if [[ -z "$STAMP" ]]; then
  echo "Usage: sudo bash $0 <timestamp>"
  echo "Example: sudo bash $0 20260316_164132"
  exit 1
fi

if [[ "${EUID}" -ne 0 ]]; then
  echo "Please run as root: sudo bash $0 $STAMP"
  exit 1
fi

for file in user.rules before.rules after.rules user6.rules before6.rules after6.rules; do
  src="/etc/ufw/${file}.${STAMP}"
  dst="/etc/ufw/${file}"
  if [[ ! -f "$src" ]]; then
    echo "Missing backup file: $src" >&2
    exit 1
  fi
  cp "$src" "$dst"
done

ufw reload
ufw status verbose


path: scripts/verify-firewall.sh
content: #!/usr/bin/env bash
set -euo pipefail

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "Missing required command: $1" >&2
    exit 1
  }
}

need_cmd ufw
need_cmd ss

echo '== UFW status =='
sudo ufw status verbose || true

echo
echo '== Listening ports =='
ss -ltnp || true

echo
echo '== OpenClaw audit =='
openclaw security audit --deep || true

echo
echo '== OpenClaw gateway status =='
openclaw gateway status || true


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