mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 05:34:55 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
146 lines
5.9 KiB
Python
146 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for configuring and auditing NextDNS zero trust DNS filtering via API."""
|
|
|
|
import requests
|
|
import json
|
|
import argparse
|
|
from datetime import datetime, timezone
|
|
|
|
NEXTDNS_API = "https://api.nextdns.io"
|
|
|
|
|
|
def get_profile(api_key, profile_id):
|
|
"""Retrieve NextDNS profile configuration."""
|
|
headers = {"X-Api-Key": api_key}
|
|
resp = requests.get(f"{NEXTDNS_API}/profiles/{profile_id}", headers=headers, timeout=15)
|
|
resp.raise_for_status()
|
|
profile = resp.json()
|
|
print(f"[*] Profile: {profile.get('name', profile_id)}")
|
|
print(f" Security: {json.dumps(profile.get('security', {}), indent=2)[:200]}")
|
|
return profile
|
|
|
|
|
|
def audit_security_settings(api_key, profile_id):
|
|
"""Audit security features enabled on a NextDNS profile."""
|
|
headers = {"X-Api-Key": api_key}
|
|
resp = requests.get(f"{NEXTDNS_API}/profiles/{profile_id}/security", headers=headers, timeout=15)
|
|
resp.raise_for_status()
|
|
security = resp.json()
|
|
findings = []
|
|
checks = {
|
|
"threatIntelligenceFeeds": "Threat intelligence feeds",
|
|
"aiDetection": "AI-driven threat detection",
|
|
"googleSafeBrowsing": "Google Safe Browsing",
|
|
"cryptojacking": "Cryptojacking protection",
|
|
"dnsRebinding": "DNS rebinding protection",
|
|
"idnHomographs": "IDN homograph protection",
|
|
"typosquatting": "Typosquatting protection",
|
|
"dga": "DGA domain protection",
|
|
"nrd": "Newly registered domains blocking",
|
|
"ddns": "Dynamic DNS blocking",
|
|
"csam": "CSAM blocking",
|
|
}
|
|
for key, label in checks.items():
|
|
enabled = security.get(key, False)
|
|
status = "ENABLED" if enabled else "DISABLED"
|
|
if not enabled:
|
|
findings.append({"feature": label, "key": key, "severity": "MEDIUM"})
|
|
print(f" [{'+' if enabled else '!'}] {label}: {status}")
|
|
print(f"\n[*] {len(findings)} security features disabled")
|
|
return findings
|
|
|
|
|
|
def get_query_logs(api_key, profile_id, limit=100):
|
|
"""Retrieve recent DNS query logs for analysis."""
|
|
headers = {"X-Api-Key": api_key}
|
|
params = {"limit": limit}
|
|
resp = requests.get(f"{NEXTDNS_API}/profiles/{profile_id}/logs",
|
|
headers=headers, params=params, timeout=15)
|
|
resp.raise_for_status()
|
|
logs = resp.json().get("data", [])
|
|
blocked = [l for l in logs if l.get("status") == "blocked"]
|
|
print(f"[*] Query logs: {len(logs)} total, {len(blocked)} blocked")
|
|
for entry in blocked[:10]:
|
|
print(f" [BLOCKED] {entry.get('domain')} - reason: {entry.get('reasons', ['?'])[0]}")
|
|
return logs
|
|
|
|
|
|
def get_analytics(api_key, profile_id, period="last30d"):
|
|
"""Retrieve DNS analytics and threat statistics."""
|
|
headers = {"X-Api-Key": api_key}
|
|
endpoints = {
|
|
"queries": f"/profiles/{profile_id}/analytics/status",
|
|
"domains": f"/profiles/{profile_id}/analytics/domains",
|
|
"blocked_reasons": f"/profiles/{profile_id}/analytics/blockedReasons",
|
|
}
|
|
analytics = {}
|
|
for name, path in endpoints.items():
|
|
resp = requests.get(f"{NEXTDNS_API}{path}", headers=headers,
|
|
params={"from": f"-{period}"}, timeout=15)
|
|
if resp.status_code == 200:
|
|
analytics[name] = resp.json()
|
|
if "queries" in analytics:
|
|
data = analytics["queries"].get("data", [])
|
|
total = sum(d.get("queries", 0) for d in data)
|
|
blocked = sum(d.get("blockedQueries", 0) for d in data)
|
|
print(f"[*] Analytics ({period}): {total} queries, {blocked} blocked "
|
|
f"({blocked/total*100:.1f}%)" if total else "[*] No query data")
|
|
return analytics
|
|
|
|
|
|
def check_denylist(api_key, profile_id):
|
|
"""Check configured denylists and custom blocked domains."""
|
|
headers = {"X-Api-Key": api_key}
|
|
resp = requests.get(f"{NEXTDNS_API}/profiles/{profile_id}/denylist",
|
|
headers=headers, timeout=15)
|
|
resp.raise_for_status()
|
|
denylist = resp.json()
|
|
entries = denylist.get("data", [])
|
|
print(f"[*] Denylist entries: {len(entries)}")
|
|
for e in entries[:20]:
|
|
print(f" {e.get('id', 'unknown')}: active={e.get('active', True)}")
|
|
return entries
|
|
|
|
|
|
def generate_report(profile, findings, logs, analytics, output_path):
|
|
"""Generate NextDNS audit report."""
|
|
report = {
|
|
"audit_date": datetime.now(timezone.utc).isoformat(),
|
|
"profile": profile.get("name", "unknown"),
|
|
"security_findings": findings,
|
|
"blocked_queries_sample": [l for l in logs if l.get("status") == "blocked"][:20],
|
|
"analytics_summary": analytics,
|
|
}
|
|
with open(output_path, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"\n[*] Report saved to {output_path}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="NextDNS Zero Trust DNS Audit Agent")
|
|
parser.add_argument("action", choices=["audit", "logs", "analytics", "denylist", "full-audit"])
|
|
parser.add_argument("--api-key", required=True, help="NextDNS API key")
|
|
parser.add_argument("--profile", required=True, help="NextDNS profile ID")
|
|
parser.add_argument("-o", "--output", default="nextdns_audit.json")
|
|
args = parser.parse_args()
|
|
|
|
if args.action == "audit":
|
|
get_profile(args.api_key, args.profile)
|
|
audit_security_settings(args.api_key, args.profile)
|
|
elif args.action == "logs":
|
|
get_query_logs(args.api_key, args.profile)
|
|
elif args.action == "analytics":
|
|
get_analytics(args.api_key, args.profile)
|
|
elif args.action == "denylist":
|
|
check_denylist(args.api_key, args.profile)
|
|
elif args.action == "full-audit":
|
|
prof = get_profile(args.api_key, args.profile)
|
|
findings = audit_security_settings(args.api_key, args.profile)
|
|
logs = get_query_logs(args.api_key, args.profile)
|
|
analytics = get_analytics(args.api_key, args.profile)
|
|
generate_report(prof, findings, logs, analytics, args.output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|