mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-05-31 18:29:29 +02:00
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:
@@ -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 />} />
|
||||
|
||||
@@ -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' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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 => (
|
||||
|
||||
Reference in New Issue
Block a user