# Client Bot Security

> Full-spectrum security audit for client Telegram bots across a multi-gateway fleet (Hermes + OpenClaw). Covers bot inventory & topology mapping, token provisioning security, SSH key hygiene, authorized_keys audit, secrets map documentation, and bot lifecycle management (free→assigned→active→retired).

- Skill: `s3yed/client-bot-security-3` (Agent Skill)
- Install (CLI): `npx skillmds@latest add s3yed/client-bot-security-3`
- Raw SKILL.md: https://api.skillmd.com/api/skills/s3yed/client-bot-security-3/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: S3YED (https://skillmd.com/u/s3yed)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/s3yed/client-bot-security-3

---


# Client Bot Security Audit & Hardening

## When to Use

Activate this skill when:
- User asks to "secure all client bots" or "make me the most secure CTO"
- Auditing security posture of deployed Telegram bots
- Inventorying which bots run where and with what secrets
- Checking SSH key hygiene for bot-hosting fleet nodes
- Setting up a bot provisioning pipeline
- Reviewing or creating the bot-provisioning-ledger.json

## Bot Discovery & Inventory

### 1. Find Bot Avatars

Bot avatars in the workspace reveal which Telegram bots exist:

```bash
ls -la ~/clawd/assets/agent-avatars/
# Pattern: <name>-<handle>.jpg
# e.g. priva-Privanotifybot.jpg → @Privanotifybot
```

### 2. Find Bot Projects

Search the workspace for bot-related projects:

```bash
ls ~/clawd/projects/ | grep -iE '(bot|telegram|notify|agent)'
```

### 3. Find Bot Configs & Secrets

Three layers of secret storage:
- `.weblyfe-secrets/` — central secrets vault (appie-1 only)
- Hermes `.env` files — per-node (appie-2: `/root/.hermes/.env`)
- OpenClaw config — (eugi: `/root/.openclaw/openclaw.json`)

```bash
# Central vault
ls -la ~/.weblyfe-secrets/
# → bot-provisioning-ledger.json (token_ref map)
# → bot-provisioning-pool.env (raw tokens for free pool)
# → telegram-bot.env (current bot token for this agent)
# → .env (all other API keys)

# Fleet node Hermes
ssh <user>@<tailscale_ip> "cat /root/.hermes/.env | grep -iE 'BOT|TOKEN'"

# Fleet node OpenClaw
ssh <user>@<tailscale_ip> "cat /root/.openclaw/openclaw.json"
```

### 4. Bot Topology Map

Document per bot:

| Field | Example |
|-------|---------|
| name | Appie-3 CTO |
| handle | @eppieweblyfebot |
| token_ref | TELEGRAM_BOT_TOKEN (in telegram-bot.env) |
| host | appie-1 (this Mac Mini) |
| gateway | Hermes |
| status | active / assigned / free / retired |

The bot-provisioning-ledger.json tracks:
```json
{
  "name": "Appie Doctor",
  "handle": "@weblyfebot",
  "token_ref": "APPIE_DOCTOR_BOT_TOKEN",
  "status": "assigned",
  "box": "mac-mini (appie-1)",
  "sale": null,
  "assigned_at": "2026-06-11",
  "notes": "..."
}
```

### 5. Gateways & Running Processes

Check what's running on each fleet node:

```bash
# Hermes gateway detection
ssh <host> "ps aux | grep -iE '(gateway|hermes)' | grep -v grep"
# → /usr/local/lib/hermes-agent/venv/bin/python -m hermes_cli.main gateway run --replace

# OpenClaw gateway detection
ssh <host> "ps aux | grep -iE '(openclaw|openclaw-gateway)' | grep -v grep"
# → openclaw-gateway

# Open ports
ssh <host> "ss -tlnp"  # Linux
# Hermes: varies (gateway port in config)
# OpenClaw: typically 18789 (HTTP API) + 18791 (internal)
```

## SSH Key Audit Procedure

> **📘 Reference:** See `references/ssh-connectivity-troubleshooting.md` for a systematic SSH failure diagnosis flow (macOS vs Linux, rate-limiting avoidance, Tailscale SSH quirks, SSH policy inspection, verbose debugging, and common failure modes).

### 1. Inventory Authorized Keys

```bash
for host in "<user>@<ip1>" "<user>@<ip2>"; do
  echo "=== $host ==="
  ssh -o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=no \
    -i "$HOME/.ssh/<key>" "$host" \
    "cat /root/.ssh/authorized_keys | awk '{print \$3}'"
done
```

This reveals:
- How many keys are authorized (baseline for changes)
- Who has access (the comment field = identity)
- Stale/decommissioned keys

### 2. Check for Deploy Keys

```bash
ssh <host> "ls -la /root/.ssh/ | grep -v authorized_keys | grep -v known_hosts"
```

Deploy keys (for CI/CD or service accounts) should be in separate files with clear filenames.

### 3. Audit SSH Config

```bash
ssh <host> "cat /root/.ssh/config"
```

Check for:
- `PasswordAuthentication no`
- `PubkeyAuthentication yes`
- No wildcard `Host *` that exposes sensitive hosts

### 4. Root Login Assessment

Determine if the node allows direct root SSH. If so, document and flag for hardening:
```bash
ssh <host> "grep -i 'permitrootlogin\|passwordauthentication' /etc/ssh/sshd_config"
```

## Bot Token Security

### Where Tokens Live

| Location | Risk | Mitigation |
|----------|------|------------|
| `~/.weblyfe-secrets/` (appie-1) | Medium (local machine compromise) | chmod 600, no git track |
| `/root/.hermes/.env` (appie-2) | Medium (VPS compromise) | chmod 600, root-only read |
| OpenClaw config (eugi) | Medium (VPS compromise) | chmod 600 on config dir |
| Bot provisioning pool | High (bulk token leak) | Never echo to chat/logs |

### Token Discipline Rules

1. **Never** echo token values to chat, logs, or commits
2. **Never** put tokens in `package.json`, `bot.py`, or any tracked file
3. **Always** chmod 600 on .env files
4. **Always** use `token_ref` in the ledger, not raw tokens
5. **Token rotation**: rotate on each bot reassignment or security incident
6. **Provisioning**: new bots → pool tokens → assign in ledger → point env → test → activate

### Gitleaks for Token Detection

```bash
# Scan all project dirs for leaked tokens
gitleaks detect --source ~/clawd/projects --no-git --config ~/.gitleaks.toml --verbose
```

### Bot Lifecycle

```
free → assigned → active → retired
```

- **free**: token in provisioning pool, no box assigned
- **assigned**: token linked to a box/env, not yet tested
- **active**: confirmed running, serving users
- **retired**: token revoked, bot removed, ledger archived

## Secrets Map

Maintain a secrets map that documents:
- **Secret**: env var name
- **Location**: which file(s) and node(s)
- **Access**: which users/processes can read it
- **Rotation**: last rotated, rotation policy
- **Scope**: which bot(s) depend on it

Format:
```markdown
| Secret | Location | Access | Scope |
|--------|----------|--------|-------|
| TELEGRAM_BOT_TOKEN (Appie-3) | `~/.weblyfe-secrets/telegram-bot.env` | root@appie-1 | Appie-3 CTO |
| TELEGRAM_BOT_TOKEN (Appie-2) | `/root/.hermes/.env` | root@appie-2 | Appie-2 gateway |
```

## Client Bot Security Checklist

Run this checklist for each new client bot deployment:

- [ ] Bot token in `.weblyfe-secrets/bot-provisioning-pool.env` (not tracked)
- [ ] Bot registered in `bot-provisioning-ledger.json` with token_ref
- [ ] Status set to `assigned` (with box, sale, assigned_at)
- [ ] SSH access to host verified (key + user)
- [ ] authorized_keys reviewed (only current keys)
- [ ] .env file has chmod 600
- [ ] Gateway verified running (Hermes or OpenClaw)
- [ ] Bot responds to /start (telegram smoke test)
- [ ] Gitleaks scan passes on project dir
- [ ] Dep audit clean (npm audit / safety check)
- [ ] Tailscale ACL permits bot-to-user traffic

## Pitfalls

- **spark-atlas SSH key broken**: Key `id_ed25519_spark` for root@100.69.197.43 returns `Permission denied`. May need a different user/key. Don't assume all fleet nodes are reachable.
- **Bot provisioning pool leak**: The pool env has 5 unassigned bot tokens. If leaked, all 5 are compromised. Guard with chmod 600.
- **OpenClaw vs Hermes configs are different**: OpenClaw stores tokens in `openclaw.json` (JSON), not `.env`. Know which gateway runs on which node before looking.
- **Ghost nodes return**: Nodes that were offline >30d may have different SSH keys when they come back. Verify before re-adding to active scan.
- **authorized_keys drift**: Manual SSH key additions by other agents/users can go undocumented. Compare against a known-good baseline.
