
Security Monitor
- 36 installs
- 82 repo stars
- Updated August 2, 2026
- aaaaqwq/claude-code-skills
security-monitor is a skill that runs continuous real-time security monitoring on a Clawdbot deployment and alerts on intrusions and anomalies.
About
security-monitor is a skill that runs continuous security monitoring on a Clawdbot deployment. It watches for intrusions, unusual API calls, credential-usage patterns, port scans, process anomalies, and file changes, then alerts via console, JSON logs, or Telegram. A developer runs it as a daemon (via PM2 or systemd) to keep watch after deployment. It requires no external dependencies and pairs with a separate one-time security-audit skill.
- Runs continuous real-time security monitoring as a background process or daemon
- Detects brute-force logins, port scanning, process anomalies, and file changes
- Emits console output, JSON alert logs, and configurable Telegram alerts
Security Monitor by the numbers
- 36 all-time installs (skills.sh)
- Ranked #1,451 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
security-monitor capabilities & compatibility
- Capabilities
- intrusion detection · anomaly detection · security monitoring · breach alerting
- Use cases
- security audit
- Pricing
- Free
What security-monitor says it does
Real-time security monitoring for Clawdbot. Detects intrusions, unusual API calls, credential usage patterns, and alerts on breaches.
Run continuous security monitoring to detect breaches, intrusions, and unusual activity on your Clawdbot deployment.
npx skills add https://github.com/aaaaqwq/claude-code-skills --skill security-monitorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 36 |
|---|---|
| repo stars | ★ 82 |
| Last updated | August 2, 2026 |
| Repository | aaaaqwq/claude-code-skills ↗ |
What it does
Continuously monitor a deployment for intrusions, anomalies, and file changes, alerting on breaches.
Who is it for?
Keeping continuous watch on a deployed server or bot for intrusions and unusual activity
Skip if: One-time security audits (use the separate security-audit skill) or code-level SAST
When should I use this skill?
You want continuous, real-time breach and anomaly detection running on a live deployment
What you get
A running daemon that detects and alerts on intrusions, port scans, and file changes
- continuous monitoring process
- JSON alert log
- optional Telegram alerts
By the numbers
- 5 monitored threat types (brute force, port scan, process, file, container)
- default 60s scan interval
Files
Security Monitor Skill
When to use
Run continuous security monitoring to detect breaches, intrusions, and unusual activity on your Clawdbot deployment.
Setup
No external dependencies required. Runs as a background process.
How to
Start real-time monitoring
node skills/security-monitor/scripts/monitor.cjs --interval 60Run in daemon mode (background)
node skills/security-monitor/scripts/monitor.cjs --daemon --interval 60Monitor for specific threats
node skills/security-monitor/scripts/monitor.cjs --threats=credentials,ports,api-callsWhat It Monitors
| Threat | Detection | Response |
|---|---|---|
| Brute force attacks | Failed login detection | Alert + IP tracking |
| Port scanning | Rapid connection attempts | Alert |
| Process anomalies | Unexpected processes | Alert |
| File changes | Unauthorized modifications | Alert |
| Container health | Docker issues | Alert |
Output
- Console output (stdout)
- JSON logs at
/root/clawd/clawdbot-security/logs/alerts.log - Telegram alerts (configurable)
Daemon Mode
Use systemd or PM2 to keep monitoring active:
# With PM2
pm2 start monitor.cjs --name "clawdbot-security" -- --daemon --interval 60Combined with Security Audit
Run audit first, then monitor continuously:
# One-time audit
node skills/security-audit/scripts/audit.cjs --full
# Continuous monitoring
node skills/security-monitor/scripts/monitor.cjs --daemonRelated skills
security-audit- One-time security scan (install separately)
{
"ownerId": "kn76hg853dr5yzqyhbhk70hagh7zz7fd",
"slug": "security-monitor",
"version": "1.0.0",
"publishedAt": 1769467400470
}{
"version": 1,
"registry": "https://clawhub.ai",
"slug": "security-monitor",
"installedVersion": "1.0.0",
"installedAt": 1770443022674
}
#!/usr/bin/env node
/**
* security-monitor.cjs - Real-time security monitoring for Clawdbot
* Usage: node monitor.js [--interval 60] [--daemon] [--threats=...]
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// Configuration
const LOG_DIR = '/root/clawd/clawdbot-security/logs';
const STATE_FILE = '/root/clawd/clawdbot-security/.monitor-state.json';
const ALERT_LOG = path.join(LOG_DIR, 'alerts.log');
// State
let state = {
lastCheck: Date.now(),
failedLogins: {},
apiCalls: {},
portScans: {},
alerts: []
};
// Load state
function loadState() {
try {
state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
} catch {
state = {
lastCheck: Date.now(),
failedLogins: {},
apiCalls: {},
portScans: {},
alerts: []
};
}
}
// Save state
function saveState() {
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
}
// Logger
function log(level, message, details = {}) {
const entry = {
timestamp: new Date().toISOString(),
level,
message,
details
};
const logLine = JSON.stringify(entry);
console.log(`[${entry.timestamp}] ${level}: ${message}`);
// Write to alert log
try {
fs.appendFileSync(ALERT_LOG, logLine + '\n');
} catch {
// Ignore logging errors
}
// Store in state
state.alerts.unshift(entry);
state.alerts = state.alerts.slice(0, 100); // Keep last 100
// Telegram alert on critical
if (level === 'CRITICAL' || level === 'HIGH') {
// TODO: Send Telegram alert
}
}
// === MONITORS ===
function checkFailedLogins() {
// Check auth logs for failed login attempts
try {
const authLog = execSync('tail -100 /var/log/auth.log 2>/dev/null || tail -100 /var/log/syslog 2>/dev/null || echo ""',
{ encoding: 'utf8', timeout: 5000 });
const failedPattern = /Failed password|Failed login|Authentication failure/gi;
const matches = authLog.match(failedPattern) || [];
const now = Date.now();
const window = 3600000; // 1 hour
for (const match of matches) {
// Extract IP if possible
const ipMatch = match.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/);
if (ipMatch) {
const ip = ipMatch[0];
state.failedLogins[ip] = state.failedLogins[ip] || [];
state.failedLogins[ip].push(now);
// Clean old entries
state.failedLogins[ip] = state.failedLogins[ip].filter(t => now - t < window);
// Alert on threshold
if (state.failedLogins[ip].length >= 5) {
log('HIGH', 'Brute force detection', {
ip,
attempts: state.failedLogins[ip].length,
window: '1 hour'
});
}
}
}
} catch {
// Auth log not accessible - skip
}
}
function checkOpenPorts() {
// Quick port check - are expected ports still open?
const expectedPorts = [22, 80, 443, 3000, 8080];
try {
const ssOutput = execSync('ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null || echo ""',
{ encoding: 'utf8', timeout: 5000 });
const foundPorts = [];
const portMatch = ssOutput.match(/:(\d+)\s/g);
if (portMatch) {
for (const p of portMatch) {
const port = parseInt(p.replace(/[:\s]/g, ''));
if (port > 0) foundPorts.push(port);
}
}
// Check for unexpected ports
const unexpected = foundPorts.filter(p => !expectedPorts.includes(p));
if (unexpected.length > 0 && unexpected.length < foundPorts.length) {
log('MEDIUM', 'Unexpected ports detected', {
unexpected: unexpected.slice(0, 10),
expected: expectedPorts
});
}
} catch {
// Can't check ports - skip
}
}
function checkProcessAnomalies() {
// Check for unusual processes
try {
const psOutput = execSync('ps aux 2>/dev/null | grep -v "^USER" || echo ""',
{ encoding: 'utf8', timeout: 5000 });
const lines = psOutput.split('\n').filter(l => l.trim());
const processCount = lines.length;
// Alert if significantly more processes than usual
if (state.lastProcessCount && processCount > state.lastProcessCount * 1.5) {
log('MEDIUM', 'Process count spike detected', {
current: processCount,
previous: state.lastProcessCount,
increase: `${Math.round((processCount - state.lastProcessCount) / state.lastProcessCount * 100)}%`
});
}
state.lastProcessCount = processCount;
} catch {
// Can't check processes
}
}
function checkFileChanges() {
// Check for unexpected file changes
const watchPaths = [
'/root/clawd/skills/.env',
'/root/clawd/config',
'/root/clawd/.env'
];
for (const watchPath of watchPaths) {
try {
const stats = fs.statSync(watchPath);
const mtime = stats.mtimeMs;
if (state.lastMtimes && state.lastMtimes[watchPath]) {
if (mtime > state.lastMtimes[watchPath] && mtime > state.lastCheck) {
log('HIGH', 'File modified', {
file: watchPath,
time: new Date(mtime).toISOString()
});
}
}
state.lastMtimes = state.lastMtimes || {};
state.lastMtimes[watchPath] = mtime;
} catch {
// File doesn't exist - skip
}
}
}
function checkApiKeyUsage() {
// Check for unusual API key usage patterns
// This is a simplified check - real implementation would need API integration
try {
const envContent = fs.readFileSync('/root/clawd/skills/.env', 'utf8');
if (envContent.includes('TWITTER') || envContent.includes('KAPSO')) {
log('INFO', 'API credentials present', {
services: envContent.match(/(?:TWITTER|KAPSO|WHATSAPP)/g) || []
});
}
} catch {
// Can't read env
}
}
function checkDockerHealth() {
// Check Docker container health
try {
const dockerPs = execSync('docker ps --format json 2>/dev/null || docker ps 2>/dev/null || echo ""',
{ encoding: 'utf8', timeout: 5000 });
if (dockerPs.includes('unhealthy') || dockerPs.includes('Exited')) {
log('MEDIUM', 'Container issue detected', {
status: dockerPs.includes('unhealthy') ? 'unhealthy' : 'exited'
});
}
} catch {
// Docker not available
}
}
// === MAIN ===
async function runMonitor(options = {}) {
const {
interval = 60,
daemon = false,
threats = 'all',
logPath = ALERT_LOG
} = options;
// Ensure log directory exists
if (!fs.existsSync(LOG_DIR)) {
fs.mkdirSync(LOG_DIR, { recursive: true });
}
console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║ CLAWDBOT SECURITY MONITOR v1.0 ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');
console.log(`Monitoring interval: ${interval}s`);
console.log(`Threats: ${threats}`);
console.log(`Alert log: ${ALERT_LOG}\n`);
if (daemon) {
console.log('Running in daemon mode. Press Ctrl+C to stop.\n');
}
loadState();
const runChecks = () => {
const now = Date.now();
console.log(`\n[${new Date().toISOString()}] Running security checks...`);
checkFailedLogins();
checkOpenPorts();
checkProcessAnomalies();
checkFileChanges();
checkApiKeyUsage();
checkDockerHealth();
state.lastCheck = now;
saveState();
const alertCount = state.alerts.filter(a =>
new Date(a.timestamp).getTime() > now - 3600000
).length;
console.log(`[${new Date().toISOString()}] Checks complete. ${alertCount} alerts in last hour.`);
};
// Initial run
runChecks();
if (daemon) {
// Continuous monitoring
setInterval(runChecks, interval * 1000);
}
}
// Run if called directly
if (require.main === module) {
const args = process.argv.slice(2);
const options = {
interval: parseInt(args.find(a => a.startsWith('--interval='))?.[1] ||
args.find(a => a.startsWith('--interval '))?.[1] || '60'),
daemon: args.includes('--daemon'),
threats: args.find(a => a.startsWith('--threats='))?.[1] || 'all'
};
runMonitor(options).catch(e => {
console.error('Monitor error:', e.message);
process.exit(1);
});
}
module.exports = { runMonitor, checkFailedLogins, checkOpenPorts, checkProcessAnomalies, checkFileChanges };