- workspace: capmetro-monitor, github-notifications, model-selector - workspace-security: vt-monitor, monitor-unauthorized - workspace-home: cron-manager, monitor-unauthorized - extensions: vt-sentinel (VT-Sentinel plugin) Includes sync.sh for pull/push, README, AGENTS.md, .gitignore.
7.0 KiB
name, description, metadata
| name | description | metadata | ||||
|---|---|---|---|---|---|---|
| monitor-unauthorized | Monitor and report unauthorized WebSocket gateway connections. Parses logs every 30 minutes, detects new and returning IPs, and manages per-IP Discord threads for tracking unauthorized access attempts. |
|
Monitor Unauthorized Gateway Connections
Detects and tracks unauthorized WebSocket connection attempts to the OpenClaw gateway. Maintains per-IP Discord threads for ongoing tracking.
Usage
# Cron tool (every 30 minutes)
bash skills/monitor-unauthorized/scripts/cron-wrapper.sh
Architecture
Scripts (data layer — no Discord/OpenClaw calls)
| Script | Purpose |
|---|---|
scripts/log-splitter.sh |
Extracts unauthorized connection entries from the gateway log into /tmp/openclaw/unauthorized-connections.log (incremental, byte-offset tracked) |
scripts/check.sh |
Reads new entries from the unauthorized log, categorizes IPs as new_ips or returning_ips, updates seen-connections.json |
scripts/index-threads.sh |
Manages the thread index — lookup, record, and staleness checks. The index maps IPs to their Discord thread session keys |
scripts/cron-wrapper.sh |
Orchestrates the above scripts and outputs structured ACTION blocks for the agent |
Agent (action layer — thread management via OpenClaw tools)
The agent parses the cron-wrapper output and handles all Discord thread operations using OpenClaw's built-in session and thread tools.
Cron Behavior
log-splitter.shextracts new unauthorized connection log lines (incremental)check.shprocesses new entries, outputs JSON withnew_ips[]andreturning_ips[]cron-wrapper.shformats ACTION blocks the agent must parse and act on- If no new activity: script produces no output → agent replies
NO_REPLY
Parsing Cron Output
The cron-wrapper outputs ACTION blocks. Parse them as follows:
ACTION:INDEX_THREADS
The thread index is missing or stale. You must refresh it before processing connections.
Steps:
- List all threads in the security Discord channel (
1471181304782389381) - For each thread whose name starts with
🚨and containsunauthorized gateway access:- Extract the IP address from the thread name (format:
🚨 <ip> — unauthorized gateway access) - Record it:
bash scripts/index-threads.sh record "<ip>" "<session_key>" "<thread_name>"
- Extract the IP address from the thread name (format:
- The session key format is:
agent:security:discord:channel:1471181304782389381:thread:<thread_name>
ACTION:NEW_THREAD
A new unauthorized IP was detected. Create a thread and report.
Format:
ACTION:NEW_THREAD
IP:<ip_address>
---
<report content>
---END_ACTION---
Steps:
- Construct the thread name:
🚨 <ip> — unauthorized gateway access - Construct the session key:
agent:security:discord:channel:1471181304782389381:thread:<thread_name> - Use
sessions_sendto send the report content (between---and---END_ACTION---) to that session key. This creates the thread if it doesn't exist. - Record the thread in the index:
bash scripts/index-threads.sh record "<ip>" "<session_key>"
ACTION:UPDATE_THREAD
A previously-seen IP has new connection attempts. Update the existing thread.
Format:
ACTION:UPDATE_THREAD
IP:<ip_address>
SESSION_KEY:<session_key or empty>
---
<update content>
---END_ACTION---
Steps:
- If
SESSION_KEYis provided and non-empty, use it directly - If
SESSION_KEYis empty, construct it:agent:security:discord:channel:1471181304782389381:thread:🚨 <ip> — unauthorized gateway access - Use
sessions_sendto post the update content to that session key - Update the index:
bash scripts/index-threads.sh record "<ip>" "<session_key>"
Thread Index Management
The thread index (memory/thread-index.json) maps IPs to their Discord thread session keys. This avoids redundant thread creation and enables reliable updates.
One-Time Bootstrap
On first run (or when the index is missing), the agent must:
- List all existing threads in channel
1471181304782389381 - Identify threads matching the
🚨 <ip> — unauthorized gateway accesspattern - Record each one via
scripts/index-threads.sh record
Ongoing Maintenance
- After creating a new thread (
ACTION:NEW_THREAD), alwaysrecordit in the index - After sending an update (
ACTION:UPDATE_THREAD), alwaysrecordit to refresh timestamps - The index auto-expires after 24 hours; the cron-wrapper will emit
ACTION:INDEX_THREADSwhen a refresh is needed
Index Script Commands
# Check if index needs refresh
bash scripts/index-threads.sh needs-refresh
# Returns: "fresh" (exit 1), "stale" (exit 0), or "missing" (exit 0)
# Look up a thread by IP
bash scripts/index-threads.sh lookup "1.2.3.4"
# Returns: JSON with session_key, thread_name, etc. (exit 0 = found, exit 1 = not found)
# Record/update a thread entry
bash scripts/index-threads.sh record "1.2.3.4" "agent:security:discord:channel:...:thread:..." "🚨 1.2.3.4 — unauthorized gateway access"
# Check index status
bash scripts/index-threads.sh status
# Returns: JSON with entry count, age, staleness
Storage Files
| File | Location | Purpose |
|---|---|---|
seen-connections.json |
Skill directory | All IPs ever seen — first_seen, last_seen, total_attempts, metadata |
authorized-ips.json |
Skill directory | Whitelist — these IPs are silently skipped |
memory/thread-index.json |
State directory | Maps IPs to Discord thread session keys |
memory/unauth-splitter-offset |
State directory | Byte offset for log-splitter (gateway log) |
memory/unauth-check-offset |
State directory | Byte offset for check (unauthorized log) |
Authorized IPs (Whitelist)
Edit authorized-ips.json to suppress reporting for known IPs:
{
"whitelist": ["127.0.0.1", "::1", "localhost", "192.168.1.100"]
}
Log Files
| Log | Path | Contents |
|---|---|---|
| Gateway log | /tmp/openclaw/openclaw.log |
Full OpenClaw gateway log (source) |
| Unauthorized log | /tmp/openclaw/unauthorized-connections.log |
Extracted unauthorized connection entries only |
What This Monitors
Gateway WebSocket authorization failures containing forwardedFor IP addresses. Specifically:
- Entries with
"forwardedFor"in the JSON log - Entries with cause
"unauthorized"or"pairing-required"
Example Agent Flow
1. Cron fires → bash scripts/cron-wrapper.sh
2. Output contains ACTION:INDEX_THREADS → agent lists threads, records them
3. Output contains ACTION:NEW_THREAD for IP 203.0.113.42 →
a. agent constructs session key
b. agent calls sessions_send with report content
c. agent runs: bash scripts/index-threads.sh record "203.0.113.42" "<key>"
4. Output contains ACTION:UPDATE_THREAD for IP 198.51.100.7 →
a. agent uses SESSION_KEY from output (or constructs it)
b. agent calls sessions_send with update content
c. agent runs: bash scripts/index-threads.sh record "198.51.100.7" "<key>"
5. No output → agent replies NO_REPLY