secubox-openwrt/package/secubox/secubox-cve-triage/files/usr/lib/cve-triage/analyzer.sh
CyberMind-FR 44493ebfe3 feat: Add CVE Triage Agent and Vortex DNS, fix webmail login
New Packages:
- secubox-cve-triage: AI-powered CVE analysis and vulnerability management
  - NVD API integration for CVE data
  - CrowdSec CVE alert correlation
  - LocalAI-powered impact analysis
  - Approval workflow for patch recommendations
  - Multi-source monitoring (opkg, LXC, Docker)

- luci-app-cve-triage: Dashboard with alerts, pending queue, risk score

- secubox-vortex-dns: Meshed multi-dynamic subdomain delegation
  - Master/slave hierarchical DNS delegation
  - Wildcard domain management
  - First Peek auto-registration
  - Gossip-based exposure config sync
  - Submastering for nested hierarchies

Fixes:
- Webmail 401 login: config.docker.inc.php was overriding IMAP host
  to ssl://mail.secubox.in:993 which Docker couldn't reach
- Fixed mailctl webmail configure to use socat proxy (172.17.0.1:10143)

Documentation:
- Added LXC cgroup:mixed fix to FAQ-TROUBLESHOOTING.md
- Updated CLAUDE.md to include FAQ consultation at startup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 12:19:54 +01:00

198 lines
5.5 KiB
Bash

#!/bin/sh
# CVE Triage - Analyzer Module
# Uses LocalAI to analyze CVE impact and generate recommendations
# Check LocalAI availability
check_localai() {
local url="${localai_url:-http://127.0.0.1:8081}"
wget -q -O /dev/null --timeout=3 "${url}/v1/models" 2>/dev/null
}
# Call LocalAI chat completion
localai_complete() {
local prompt="$1"
local max_tokens="${2:-1024}"
local url="${localai_url:-http://127.0.0.1:8081}"
local model="${localai_model:-tinyllama-1.1b-chat-v1.0.Q4_K_M}"
# Escape prompt for JSON
local escaped_prompt=$(echo "$prompt" | sed 's/\\/\\\\/g; s/"/\\"/g' | tr '\n' ' ')
local request=$(cat <<EOF
{
"model": "$model",
"messages": [
{"role": "system", "content": "You are a cybersecurity CVE analyst for SecuBox, an OpenWrt-based security appliance running on ARM64. Provide concise, actionable security analysis."},
{"role": "user", "content": "$escaped_prompt"}
],
"max_tokens": $max_tokens,
"temperature": 0.3
}
EOF
)
local response=$(echo "$request" | wget -q -O - --post-data=- \
--header="Content-Type: application/json" \
"${url}/v1/chat/completions" 2>/dev/null)
echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null
}
# Analyze a single CVE with LocalAI
analyze_cve() {
local cve_id="$1"
local description="$2"
local cvss="$3"
local affected_pkg="$4"
if ! check_localai; then
log_warn "LocalAI not available, using basic analysis"
basic_analyze_cve "$cve_id" "$cvss" "$affected_pkg"
return
fi
local prompt="Analyze this CVE for an OpenWrt ARM64 security appliance:
CVE: $cve_id
CVSS Score: $cvss
Affected Package: ${affected_pkg:-unknown}
Description: $description
Provide a JSON response with these fields:
1. impact_level: critical/high/medium/low
2. exploitability: easy/moderate/difficult/theoretical
3. affects_openwrt: true/false (is this relevant to OpenWrt/embedded Linux?)
4. action: patch/mitigate/monitor/ignore
5. mitigation: brief mitigation steps if patch unavailable
6. urgency: immediate/soon/scheduled/none
Respond ONLY with valid JSON, no explanation."
local analysis=$(localai_complete "$prompt" 512)
# Validate JSON response
if echo "$analysis" | jsonfilter -e '@.impact_level' >/dev/null 2>&1; then
echo "$analysis"
else
# Fallback to basic analysis
basic_analyze_cve "$cve_id" "$cvss" "$affected_pkg"
fi
}
# Basic CVE analysis without AI
basic_analyze_cve() {
local cve_id="$1"
local cvss="$2"
local affected_pkg="$3"
local impact="low"
local action="monitor"
local urgency="scheduled"
# Determine impact based on CVSS
if [ -n "$cvss" ]; then
local cvss_int=$(echo "$cvss" | cut -d. -f1)
if [ "$cvss_int" -ge 9 ]; then
impact="critical"
action="patch"
urgency="immediate"
elif [ "$cvss_int" -ge 7 ]; then
impact="high"
action="patch"
urgency="soon"
elif [ "$cvss_int" -ge 4 ]; then
impact="medium"
action="mitigate"
urgency="scheduled"
fi
fi
cat <<EOF
{
"impact_level": "$impact",
"exploitability": "unknown",
"affects_openwrt": true,
"action": "$action",
"mitigation": "Update ${affected_pkg:-affected package} to latest version",
"urgency": "$urgency"
}
EOF
}
# Analyze multiple CVEs and generate recommendations
analyze_cves_batch() {
local cves="$1"
local min_severity="${min_severity:-high}"
local results='[]'
echo "$cves" | jsonfilter -e '@[*]' 2>/dev/null | while read -r cve_data; do
local cve_id=$(echo "$cve_data" | jsonfilter -e '@.cve' 2>/dev/null)
local description=$(echo "$cve_data" | jsonfilter -e '@.description' 2>/dev/null)
local cvss=$(echo "$cve_data" | jsonfilter -e '@.cvss' 2>/dev/null)
local severity=$(echo "$cve_data" | jsonfilter -e '@.severity' 2>/dev/null)
local affected_pkg=$(echo "$cve_data" | jsonfilter -e '@.affected_package' 2>/dev/null)
# Filter by minimum severity
case "$min_severity" in
critical)
[ "$severity" != "critical" ] && continue
;;
high)
[ "$severity" != "critical" ] && [ "$severity" != "high" ] && continue
;;
medium)
[ "$severity" = "low" ] && continue
;;
esac
log_info "Analyzing $cve_id (CVSS: $cvss)..."
local analysis=$(analyze_cve "$cve_id" "$description" "$cvss" "$affected_pkg")
# Merge CVE data with analysis
printf '{"cve":"%s","cvss":%s,"severity":"%s","affected_package":"%s","analysis":%s}\n' \
"$cve_id" "${cvss:-0}" "$severity" "$affected_pkg" "$analysis"
done | json_slurp
}
# Generate security posture summary
generate_summary() {
local analyzed_cves="$1"
if ! check_localai; then
echo '{"summary":"LocalAI unavailable. Manual review required.","risk_score":0}'
return
fi
local cve_count=$(echo "$analyzed_cves" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
local critical_count=$(echo "$analyzed_cves" | jsonfilter -e '@[*].severity' 2>/dev/null | grep -c "critical")
local high_count=$(echo "$analyzed_cves" | jsonfilter -e '@[*].severity' 2>/dev/null | grep -c "high")
local prompt="Summarize the security posture based on these CVE findings:
Total CVEs analyzed: $cve_count
Critical: $critical_count
High: $high_count
CVE Details:
$(echo "$analyzed_cves" | head -c 2000)
Provide a brief (2-3 sentences) executive summary and a risk score from 0-100.
Format as JSON: {\"summary\":\"...\",\"risk_score\":N}"
local summary=$(localai_complete "$prompt" 256)
# Validate JSON
if echo "$summary" | jsonfilter -e '@.summary' >/dev/null 2>&1; then
echo "$summary"
else
cat <<EOF
{
"summary": "Found $cve_count CVEs ($critical_count critical, $high_count high). Immediate attention required for critical vulnerabilities.",
"risk_score": $(( (critical_count * 25) + (high_count * 10) ))
}
EOF
fi
}