agentsclimarketplace

09 continuous monitoring

Skill 0xGhostCAT/claude-ai-cyber-security-skills/skills/09-continuous-monitoring

30 Claude Code Skills + 60+ integrated tools for HackerOne/Bugcrowd bug bounty hunters

Install
npx -y skills add 0xGhostCAT/claude-ai-cyber-security-skills --skill 09-continuous-monitoring

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

What its author says it does

Copied from the file, not written here

Set up nightly monitoring of subdomain changes, JS file diffs, new endpoints, and CVE matches against in-scope assets, with Discord/Slack/Telegram notifications. Use when the user has an active engagement and wants to be alerted to new attack surface without manual re-recon.

SKILL.md

13.2 KB, as published. Nobody here has run it

Continuous Monitoring

Sleep. Sub registered overnight. Discord pings. You hunt it before everyone else.

When to invoke

Trigger phrases:

  • "monitor target"
  • "alert on new subdomain"
  • "watch this program"
  • "set up continuous recon"

What we monitor

SignalWhy it mattersFrequency
New subdomainsNew attack surface, often less testedNightly
Subdomain takeover candidatesFree critical if found earlyNightly
JS file hash changesNew endpoints, removed mitigationsDaily
New endpoints in JSHidden routes shipped in deploysDaily
HTTP status changes (200 → 401 etc.)New restrictions / new exposuresDaily
New tech in fingerprintNew stack = new vuln classesWeekly
CVE matches against fingerprint0-days → 1-day exploitation windowDaily
GitHub commits to public reposSecrets, hints, new featuresHourly
Cert transparency new certsNew subdomains often pre-deployed in CTHourly
Wayback URL diffNew paths historical scanners pick upDaily

Two deployment models

A. Cron-based (your VPS, $5/month)

┌────────────────────────────────────────┐
│ DigitalOcean / Linode / Hetzner VPS    │
│  - cron jobs                           │
│  - bash scripts                        │
│  - state in ~/ccs-state/                │
│  - notify → Discord webhook            │
└────────────────────────────────────────┘

B. GitHub Actions (free, no VPS)

┌────────────────────────────────────────┐
│ GitHub Actions                         │
│  - scheduled workflows                 │
│  - state in repo artifacts             │
│  - notify → Discord webhook            │
└────────────────────────────────────────┘

We'll cover both.

Setup A — Cron on a VPS

Step 1: Notify configuration

Use notify — supports Discord/Slack/Telegram/Teams.

mkdir -p ~/.config/notify
cat > ~/.config/notify/provider-config.yaml <<EOF
discord:
  - id: "ccs-alerts"
    discord_webhook_url: "https://discord.com/api/webhooks/YOUR_WEBHOOK_HERE"
slack:
  - id: "ccs-alerts"
    slack_webhook_url: "https://hooks.slack.com/services/YOUR/WEBHOOK"
telegram:
  - id: "ccs-alerts"
    telegram_api_key: "YOUR_BOT_TOKEN"
    telegram_chat_id: "YOUR_CHAT_ID"
EOF

# Test
echo "Test alert from claude-cybersecurity-skills" | notify -id ccs-alerts -bulk

Step 2: Subdomain monitoring script

# scripts/monitor-subs.sh
#!/usr/bin/env bash
set -euo pipefail

TARGETS_FILE="$HOME/ccs-state/targets.txt"   # one root domain per line
STATE_DIR="$HOME/ccs-state"
mkdir -p "$STATE_DIR/subs"

while read TARGET; do
    OLD="$STATE_DIR/subs/$TARGET.txt"
    NEW="$STATE_DIR/subs/$TARGET.new.txt"

    # Run passive recon
    (subfinder -d "$TARGET" -all -silent;
     assetfinder --subs-only "$TARGET";
     curl -s "https://crt.sh/?q=%25.${TARGET}&output=json" | jq -r '.[].name_value' | sed 's/\*\.//g') | \
        sort -u > "$NEW"

    if [[ -f "$OLD" ]]; then
        # Diff
        DIFF=$(comm -13 <(sort "$OLD") <(sort "$NEW"))
        if [[ -n "$DIFF" ]]; then
            COUNT=$(echo "$DIFF" | wc -l)
            echo -e "🆕 New subdomains for **$TARGET** ($COUNT)\n\`\`\`\n$DIFF\n\`\`\`" | \
                notify -id ccs-alerts -bulk -silent

            # Auto-probe new ones for quick wins
            echo "$DIFF" | httpx -silent -tech-detect -title -status-code | \
                tee -a "$STATE_DIR/subs/$TARGET.probed.log" | \
                notify -id ccs-alerts -bulk -silent

            # Check for takeover candidates
            echo "$DIFF" | nuclei -t http/takeovers/ -silent -nc -severity high,critical | \
                notify -id ccs-alerts -bulk -silent
        fi
    else
        echo "[*] Initial baseline for $TARGET ($(wc -l < "$NEW") subs)"
    fi

    mv "$NEW" "$OLD"
done < "$TARGETS_FILE"

Step 3: JS file monitoring

# scripts/monitor-js.sh
#!/usr/bin/env bash
set -euo pipefail

URLS_FILE="$HOME/ccs-state/js-urls.txt"  # JS file URLs to monitor
STATE_DIR="$HOME/ccs-state/js"
mkdir -p "$STATE_DIR"

while read JS_URL; do
    HASH_FILE="$STATE_DIR/$(echo "$JS_URL" | md5sum | cut -d' ' -f1).hash"
    CURRENT_HASH=$(curl -s "$JS_URL" | md5sum | cut -d' ' -f1)

    if [[ -f "$HASH_FILE" ]]; then
        OLD_HASH=$(cat "$HASH_FILE")
        if [[ "$OLD_HASH" != "$CURRENT_HASH" ]]; then
            # Get the diff in endpoints
            OLD_ENDPOINTS_FILE="$STATE_DIR/$(echo "$JS_URL" | md5sum | cut -d' ' -f1).endpoints"

            curl -s "$JS_URL" > /tmp/current.js
            python3 ~/tools/LinkFinder/linkfinder.py -i /tmp/current.js -o cli 2>/dev/null | sort -u > /tmp/current.endpoints

            if [[ -f "$OLD_ENDPOINTS_FILE" ]]; then
                NEW_ENDPOINTS=$(comm -13 <(sort "$OLD_ENDPOINTS_FILE") /tmp/current.endpoints)
                if [[ -n "$NEW_ENDPOINTS" ]]; then
                    echo -e "🔧 JS changed: $JS_URL\n**New endpoints:**\n\`\`\`\n$NEW_ENDPOINTS\n\`\`\`" | \
                        notify -id ccs-alerts -bulk -silent
                fi
            fi

            mv /tmp/current.endpoints "$OLD_ENDPOINTS_FILE"
        fi
    fi

    echo "$CURRENT_HASH" > "$HASH_FILE"
done < "$URLS_FILE"

Step 4: Cert transparency real-time

Subscribe to certstream for near-instant new-cert alerts:

# scripts/certstream-monitor.py
import certstream
import re
import requests

WEBHOOK = "https://discord.com/api/webhooks/YOUR_WEBHOOK_HERE"
TARGETS = ["target.com", "anothertarget.io"]

def callback(message, context):
    if message['message_type'] != 'certificate_update':
        return
    domains = message['data']['leaf_cert']['all_domains']
    for d in domains:
        for t in TARGETS:
            if d.endswith("." + t) or d == t:
                msg = f"🆕 New cert: `{d}` (target: {t})"
                requests.post(WEBHOOK, json={"content": msg})
                return

certstream.listen_for_events(callback, url='wss://certstream.calidog.io/')

Run as systemd service:

# /etc/systemd/system/certstream-monitor.service
[Unit]
Description=Cert Transparency Monitor
After=network.target

[Service]
ExecStart=/usr/bin/python3 /home/user/ccs-state/scripts/certstream-monitor.py
Restart=always
User=user

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now certstream-monitor

Step 5: Crontab

# Subdomain enumeration
0 3 * * * /home/user/ccs-state/scripts/monitor-subs.sh >> /var/log/ccs-monitor.log 2>&1

# JS monitoring (every 6 hours)
0 */6 * * * /home/user/ccs-state/scripts/monitor-js.sh >> /var/log/ccs-monitor.log 2>&1

# Nuclei sweep of in-scope (daily)
0 5 * * * /home/user/ccs-state/scripts/nuclei-sweep.sh >> /var/log/ccs-monitor.log 2>&1

# Weekly tech re-fingerprint
0 6 * * 1 /home/user/ccs-state/scripts/refingerprint.sh >> /var/log/ccs-monitor.log 2>&1

Setup B — GitHub Actions

.github/workflows/monitor.yml

name: BB Continuous Monitoring

on:
  schedule:
    - cron: '0 3 * * *'    # daily 3am UTC
  workflow_dispatch:        # manual trigger

jobs:
  monitor-subs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.22'

      - name: Install tools
        run: |
          go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
          go install github.com/projectdiscovery/httpx/cmd/httpx@latest
          go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
          go install github.com/projectdiscovery/notify/cmd/notify@latest
          go install github.com/tomnomnom/anew@latest

      - name: Configure notify
        run: |
          mkdir -p ~/.config/notify
          cat > ~/.config/notify/provider-config.yaml <<EOF
          discord:
            - id: "ccs-alerts"
              discord_webhook_url: "${{ secrets.DISCORD_WEBHOOK }}"
          EOF

      - name: Run monitoring
        env:
          CHAOS_KEY: ${{ secrets.CHAOS_KEY }}
        run: |
          chmod +x scripts/monitor-subs.sh
          ./scripts/monitor-subs.sh

      - name: Commit state
        run: |
          git config user.name "ccs-monitor"
          git config user.email "monitor@claude-cybersecurity-skills"
          git add state/
          git diff --staged --quiet || git commit -m "monitor: state update $(date -u +%Y-%m-%dT%H:%MZ)"
          git push

Configure secrets in GitHub repo settings:

  • DISCORD_WEBHOOK
  • CHAOS_KEY
  • (any other API keys)

Nuclei daily sweep

Hit all alive in-scope hosts with critical/high templates daily:

# scripts/nuclei-sweep.sh
#!/usr/bin/env bash
set -euo pipefail

ALIVE="$HOME/ccs-state/all-alive.txt"

nuclei -list "$ALIVE" \
    -severity critical,high \
    -rate-limit 50 \
    -bulk-size 25 \
    -concurrency 25 \
    -silent \
    -nc \
    -json -o "$HOME/ccs-state/nuclei-daily.json"

# Diff against yesterday
NEW_FINDINGS=$(comm -13 \
    <(sort "$HOME/ccs-state/nuclei-yesterday.json" 2>/dev/null) \
    <(sort "$HOME/ccs-state/nuclei-daily.json"))

if [[ -n "$NEW_FINDINGS" ]]; then
    echo -e "🚨 New nuclei findings:\n\`\`\`json\n$NEW_FINDINGS\n\`\`\`" | \
        notify -id ccs-alerts -bulk -silent
fi

cp "$HOME/ccs-state/nuclei-daily.json" "$HOME/ccs-state/nuclei-yesterday.json"

GitHub commit monitoring (for OSS targets)

# scripts/github-watch.sh
# Watches commits on target's public GitHub orgs
GH_ORGS=("target-inc" "target-oss")

for ORG in "${GH_ORGS[@]}"; do
    LAST_SHA_FILE="$HOME/ccs-state/gh-$ORG.sha"

    # Get latest events
    LATEST=$(gh api "orgs/$ORG/events" --jq '.[0].id')

    if [[ -f "$LAST_SHA_FILE" ]]; then
        OLD=$(cat "$LAST_SHA_FILE")
        if [[ "$OLD" != "$LATEST" ]]; then
            EVENTS=$(gh api "orgs/$ORG/events" --jq '.[] | select(.type=="PushEvent") | "\(.repo.name): \(.payload.commits[].message)"' | head -5)
            echo -e "📦 Activity in **$ORG**:\n$EVENTS" | notify -id ccs-alerts -bulk -silent
        fi
    fi

    echo "$LATEST" > "$LAST_SHA_FILE"
done

State structure

~/ccs-state/
├── targets.txt              ← one root domain per line
├── subs/
│   ├── target.com.txt       ← yesterday's list
│   └── target.com.probed.log
├── js/
│   ├── <hash>.hash          ← last-seen hash
│   └── <hash>.endpoints     ← last-seen endpoint list
├── js-urls.txt              ← JS files to monitor
├── all-alive.txt
├── nuclei-daily.json
├── nuclei-yesterday.json
├── gh-target-inc.sha
└── logs/

Tuning alerts (avoid notification fatigue)

# rules.yaml — what to alert on
alert_rules:
  subdomain_new:
    threshold: 1                # alert on any new sub
    quiet_hours: "22-08"        # don't ping at night
  takeover_candidate:
    threshold: 1
    severity: high              # always alert
  nuclei_finding:
    severity: [critical, high]  # skip medium/low to reduce noise
  js_change:
    only_with_new_endpoints: true  # don't alert on cosmetic changes

Cross-references

  • [[subdomain-enum]] — the engine behind monitoring
  • [[js-analysis]] — for endpoint diffs
  • [[subdomain-takeover]] — auto-check on new subs
  • [[scope-analysis]] — only alert on in-scope assets

Common pitfalls

  1. Monitoring out-of-scope assets. Alerts you can't act on. Filter first.
  2. Notification fatigue. Tune severity and quiet_hours aggressively.
  3. State loss. If ~/ccs-state/ is wiped, you re-baseline = many false "new" alerts.
  4. VPS IP blocked. Some targets ban scanner IPs. Rotate or use Cloud Run / Lambda.
  5. API rate limits. Don't run subfinder every hour — daily is enough for most.

Pro tips

  • Separate webhooks per priority (one for "new subs", one for "critical findings").
  • Use Telegram for mobile alerts — instant push.
  • Tag alerts with target name in the message for fast triage.
  • Auto-create a private issue in your private bug-bounty repo for each finding.
  • Track your "first to find" rate — measures how quickly you act on monitoring alerts.

Real-world example

[Day 1, 3am UTC]
🆕 New subdomain for target.com (1):
admin-staging.target.com  [200] Tech: Spring Boot 2.5.4, Actuator

[Day 1, 9am — you wake up]
You check: /actuator/env → exposed. CRITICAL.
Report submitted by 10am. Triaged within 2h. $5,000 bounty by EOD.

This is the difference between manual recon and automated monitoring.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.