NeuroSploit v3.2.4 - MD Agent Orchestrator Overhaul + Claude 4.6 + SmartRouter Failover

- MD Agent system restructured: real HTTP exploitation, retry with exponential backoff, reduced concurrency (2 parallel, 2s stagger)
- Claude 4.6 model support (Opus/Sonnet) with corrected API version headers
- SmartRouter true failover with provider preference cascade
- WAFResult attribute error fix in autonomous_agent.py
- CVSS data sanitization for all vulnerability database saves
- AI recon JSON parsing robustness improvements
- rebuild.sh simplified from 714 to 196 lines
- Frontend: removed unused routes, simplified Auto Pentest page
- Agent grid: reduced max tests per agent (8→5), condensed recon prompts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
CyberSecurityUP
2026-03-29 20:25:01 -03:00
parent 7563260b2b
commit 59f8f42d80
18 changed files with 1184 additions and 1367 deletions
-3
View File
@@ -17,15 +17,12 @@ import SandboxDashboardPage from './pages/SandboxDashboardPage'
import KnowledgePage from './pages/KnowledgePage'
import MCPManagementPage from './pages/MCPManagementPage'
import ProvidersPage from './pages/ProvidersPage'
import FullIATestingPage from './pages/FullIATestingPage'
function App() {
return (
<Layout>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/auto" element={<AutoPentestPage />} />
<Route path="/full-ia" element={<FullIATestingPage />} />
<Route path="/vuln-lab" element={<VulnLabPage />} />
<Route path="/terminal" element={<TerminalAgentPage />} />
<Route path="/scan/new" element={<NewScanPage />} />
+2 -1
View File
@@ -5,7 +5,8 @@ const pageTitles: Record<string, string> = {
'/scan/new': 'New Security Scan',
'/reports': 'Reports',
'/settings': 'Settings',
'/full-ia': 'FULL AI TESTING',
'/auto': 'Auto Pentest',
'/realtime': 'Real-time Task',
}
export default function Header() {
@@ -16,7 +16,6 @@ import {
Brain,
Cable,
Plug,
Crosshair,
ChevronLeft,
ChevronRight,
} from 'lucide-react'
@@ -30,7 +29,6 @@ const navGroups = [
{ path: '/auto', icon: Rocket, label: 'Auto Pentest' },
{ path: '/scan/new', icon: Bot, label: 'AI Agent' },
{ path: '/realtime', icon: Zap, label: 'Real-time Task' },
{ path: '/full-ia', icon: Crosshair, label: 'FULL AI TESTING' },
],
},
{
+77 -63
View File
@@ -14,15 +14,15 @@ import VulnAgentGrid from '../components/VulnAgentGrid'
// ─── Constants ────────────────────────────────────────────────────────────────
const PHASES = [
{ key: 'parallel', label: 'Parallel Streams', icon: Layers, range: [0, 50] as const },
{ key: 'deep', label: 'Deep Analysis', icon: Brain, range: [50, 75] as const },
{ key: 'final', label: 'Finalization', icon: Shield, range: [75, 100] as const },
{ key: 'recon', label: 'Reconnaissance', icon: Globe, range: [0, 20] as const },
{ key: 'agents', label: 'Agent Grid (108 agents)', icon: Layers, range: [20, 85] as const },
{ key: 'final', label: 'Finalization', icon: Shield, range: [85, 100] as const },
]
const STREAMS = [
{ key: 'recon', label: 'Recon', icon: Globe, color: 'blue', activeUntil: 25 },
{ key: 'junior', label: 'Junior AI', icon: Brain, color: 'purple', activeUntil: 35 },
{ key: 'tools', label: 'Tools', icon: Wrench, color: 'orange', activeUntil: 50 },
{ key: 'recon', label: 'Recon', icon: Globe, color: 'blue', activeUntil: 20 },
{ key: 'agents', label: 'Agent Grid', icon: Brain, color: 'purple', activeUntil: 85 },
{ key: 'final', label: 'Report', icon: Wrench, color: 'orange', activeUntil: 100 },
] as const
const STREAM_COLORS: Record<string, { bg: string; text: string; border: string; pulse: string }> = {
@@ -53,12 +53,10 @@ const CONFIDENCE_STYLES: Record<string, string> = {
const LOG_FILTERS = [
{ key: 'all', label: 'All', color: '' },
{ key: 'stream1', label: 'Recon', color: 'text-blue-400' },
{ key: 'stream2', label: 'Junior', color: 'text-purple-400' },
{ key: 'stream3', label: 'Tools', color: 'text-orange-400' },
{ key: 'deep', label: 'Deep', color: 'text-cyan-400' },
{ key: 'container', label: 'Container', color: 'text-cyan-300' },
{ key: 'cli_agent', label: 'CLI Agent', color: 'text-pink-400' },
{ key: 'recon', label: 'Recon', color: 'text-blue-400' },
{ key: 'agents', label: 'Agents', color: 'text-green-400' },
{ key: 'judge', label: 'Validation', color: 'text-amber-300' },
{ key: 'final', label: 'Final', color: 'text-cyan-400' },
{ key: 'error', label: 'Errors', color: 'text-red-400' },
]
@@ -88,8 +86,8 @@ interface Toast {
// ─── Utility Functions ────────────────────────────────────────────────────────
function phaseFromProgress(progress: number): number {
if (progress < 50) return 0
if (progress < 75) return 1
if (progress < 20) return 0
if (progress < 85) return 1
return 2
}
@@ -116,6 +114,15 @@ function logMessageColor(message: string): string {
if (message.startsWith('[PLAYBOOK]')) return 'text-indigo-400'
if (message.startsWith('[SITE ANALYZER]')) return 'text-emerald-400'
if (message.startsWith('[MD-AGENTS]')) return 'text-cyan-300'
if (message.startsWith('[AGENT GRID]')) return 'text-green-400'
if (message.startsWith('[PHASE 1]')) return 'text-blue-300'
if (message.startsWith('[PHASE 2]')) return 'text-purple-300'
if (message.startsWith('[PHASE 3]')) return 'text-yellow-300'
if (message.startsWith('[RECON]')) return 'text-blue-400'
if (message.startsWith('[CVE]')) return 'text-red-300'
if (message.startsWith('[CHAIN]')) return 'text-orange-300'
if (message.startsWith('[JUDGE]')) return 'text-amber-300'
if (message.includes('Starting (real HTTP)')) return 'text-green-300'
return ''
}
@@ -422,8 +429,8 @@ export default function AutoPentestPage() {
// Model selection
const [availableModels, setAvailableModels] = useState<Array<{ provider_id: string; provider_name: string; default_model: string; tier: number; available_models: string[] }>>([])
const [selectedProvider, setSelectedProvider] = useState('')
const [selectedModel, setSelectedModel] = useState('')
const [selectedProvider, setSelectedProvider] = useState('anthropic')
const [selectedModel, setSelectedModel] = useState('claude-sonnet-4-20250514')
// MD Agent selection
const [availableMdAgents, setAvailableMdAgents] = useState<Array<{ name: string; display_name: string; category: string }>>([])
@@ -739,12 +746,7 @@ export default function AutoPentestPage() {
return () => { if (pollRef.current) clearInterval(pollRef.current) }
}, [sessions, agentId, connectionLost, addToast])
// Auto-scroll logs
useEffect(() => {
if (activeTab === 'logs' && logsEndRef.current) {
logsEndRef.current.scrollIntoView({ behavior: 'smooth' })
}
}, [logs, activeTab])
// Auto-scroll logs disabled — user controls scroll position
// ─── History ──────────────────────────────────────────────────────────────
@@ -1376,48 +1378,60 @@ export default function AutoPentestPage() {
)}
{/* LLM Provider / Model Selection */}
{availableModels.length > 0 && (
<div className="mb-6 flex flex-col sm:flex-row gap-3 sm:gap-4">
<div className="flex-1">
<label className="block text-xs font-medium text-dark-400 mb-1">LLM Provider</label>
<select
value={selectedProvider}
onChange={e => {
setSelectedProvider(e.target.value)
const m = availableModels.find(m => m.provider_id === e.target.value)
if (m) setSelectedModel(m.default_model)
else setSelectedModel('')
}}
disabled={isRunning}
className="w-full px-3 py-2 bg-dark-900 border border-dark-600 rounded-lg text-sm text-white focus:outline-none focus:border-green-500 disabled:opacity-50 transition-colors"
>
<option value="">Auto (best available)</option>
{availableModels.map(m => (
<option key={m.provider_id} value={m.provider_id}>
{m.provider_name} (Tier {m.tier})
</option>
))}
</select>
</div>
<div className="flex-1">
<label className="block text-xs font-medium text-dark-400 mb-1">Model</label>
<select
value={selectedModel}
onChange={e => setSelectedModel(e.target.value)}
disabled={isRunning}
className="w-full px-3 py-2 bg-dark-900 border border-dark-600 rounded-lg text-sm text-white focus:outline-none focus:border-green-500 disabled:opacity-50 transition-colors"
>
<option value="">Auto (default)</option>
{(selectedProvider
? (availableModels.find(m => m.provider_id === selectedProvider)?.available_models || [])
: availableModels.flatMap(m => m.available_models).filter((v, i, a) => a.indexOf(v) === i)
).map(model => (
<option key={model} value={model}>{model}</option>
))}
</select>
</div>
<div className="mb-6 flex flex-col sm:flex-row gap-3 sm:gap-4">
<div className="flex-1">
<label className="block text-xs font-medium text-dark-400 mb-1">LLM Provider</label>
<select
value={selectedProvider}
onChange={e => {
setSelectedProvider(e.target.value)
const m = availableModels.find(m => m.provider_id === e.target.value)
if (m) setSelectedModel(m.default_model)
else if (e.target.value === 'anthropic') setSelectedModel('claude-sonnet-4-20250514')
else setSelectedModel('')
}}
disabled={isRunning}
className="w-full px-3 py-2 bg-dark-900 border border-dark-600 rounded-lg text-sm text-white focus:outline-none focus:border-green-500 disabled:opacity-50 transition-colors"
>
<option value="">Auto (best available)</option>
<option value="anthropic">Anthropic (Claude API)</option>
<option value="claude_code">Claude Code (OAuth)</option>
<option value="openai">OpenAI</option>
<option value="gemini">Gemini</option>
<option value="openrouter">OpenRouter</option>
{availableModels.filter(m => !['anthropic','claude_code','openai','gemini','openrouter'].includes(m.provider_id)).map(m => (
<option key={m.provider_id} value={m.provider_id}>
{m.provider_name} (Tier {m.tier})
</option>
))}
</select>
</div>
)}
<div className="flex-1">
<label className="block text-xs font-medium text-dark-400 mb-1">Model</label>
<select
value={selectedModel}
onChange={e => setSelectedModel(e.target.value)}
disabled={isRunning}
className="w-full px-3 py-2 bg-dark-900 border border-dark-600 rounded-lg text-sm text-white focus:outline-none focus:border-green-500 disabled:opacity-50 transition-colors"
>
<option value="">Auto (default)</option>
{selectedProvider === 'anthropic' || selectedProvider === 'claude_code' || selectedProvider === '' ? (
<>
<option value="claude-opus-4-20250514">Claude Opus 4</option>
<option value="claude-sonnet-4-20250514">Claude Sonnet 4</option>
<option value="claude-sonnet-4-5-20250929">Claude Sonnet 4.5</option>
<option value="claude-haiku-4-5-20251001">Claude Haiku 4.5</option>
</>
) : null}
{(selectedProvider && availableModels.find(m => m.provider_id === selectedProvider)?.available_models || [])
.filter(m => !m.startsWith('claude-'))
.map(model => (
<option key={model} value={model}>{model}</option>
))
}
</select>
</div>
</div>
{/* Multi-target textarea */}
{multiTarget && (
+2 -2
View File
@@ -369,8 +369,8 @@ export default function HomePage() {
{/* ── Quick Actions ─────────────────────────────────────── */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
{([
{ label: 'Auto Pentest', icon: Zap, to: '/auto', color: 'text-green-400', bg: 'bg-green-500/10 hover:bg-green-500/20', border: 'border-green-500/20 hover:border-green-500/40', desc: '3-stream AI testing' },
{ label: 'Full IA Testing', icon: Shield, to: '/full-ia', color: 'text-red-400', bg: 'bg-red-500/10 hover:bg-red-500/20', border: 'border-red-500/20 hover:border-red-500/40', desc: '100 vuln types' },
{ label: 'Auto Pentest', icon: Zap, to: '/auto', color: 'text-green-400', bg: 'bg-green-500/10 hover:bg-green-500/20', border: 'border-green-500/20 hover:border-green-500/40', desc: '109 agents + 100 vulns' },
{ label: 'AI Agent', icon: Shield, to: '/scan/new', color: 'text-red-400', bg: 'bg-red-500/10 hover:bg-red-500/20', border: 'border-red-500/20 hover:border-red-500/40', desc: 'Custom AI scan' },
{ label: 'Vuln Lab', icon: FlaskConical, to: '/vuln-lab', color: 'text-purple-400', bg: 'bg-purple-500/10 hover:bg-purple-500/20', border: 'border-purple-500/20 hover:border-purple-500/40', desc: 'Per-type challenges' },
{ label: 'Terminal', icon: Terminal, to: '/terminal', color: 'text-cyan-400', bg: 'bg-cyan-500/10 hover:bg-cyan-500/20', border: 'border-cyan-500/20 hover:border-cyan-500/40', desc: 'AI chat + commands' },
] as const).map(action => (