From a5badefc2918fe259486d4828e057a746797cc2e Mon Sep 17 00:00:00 2001 From: CyberSecurityUP Date: Sun, 14 Jun 2026 23:26:11 -0300 Subject: [PATCH] v3.3.0 GUI dashboard + reports + model expansion + root fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Engine: - Fix: inject IS_SANDBOX=1 so Claude Code's --dangerously-skip-permissions works under root (real backend runs were exiting rc=1 immediately) - models: expand to 40 models / 13 providers, tagged CLI vs API (NVIDIA NIM, DeepSeek, Mistral, Qwen/DashScope, Groq, Together, OpenRouter, Ollama, Gemini) — Qwen/DeepSeek/Llama usable via API - backends: on_start callback surfaces the exact argv ("what runs behind it") - orchestrator: require a Playwright screenshot per confirmed finding; collect results/activity.json; auto-generate reports after a run - report.py: HTML always + PDF via Typst engine (.typ source emitted too) Web dashboard (webgui/, stdlib only — no npm/build): - Sidebar dashboard (PentAGI-style): Run / Agents / Insights / Reports / Settings - Multi-target runs; live execution console + per-task activity; finding cards with screenshots; backend+provider+model pickers (CLI & API) - Agents tab: browse 213 + add new .md agents from the UI - Insights: interactive RL-weight + severity charts - Reports: download/preview PDF + HTML - Settings/API: execution mode, per-provider API keys, orchestrator, verbosity - Endpoints: /api/agents (GET/POST), /api/rl, /api/config, /api/reports, /reports/* + /shots/* static serving Cleanup: retire replaced web stack (frontend React, FastAPI backend, core orchestration, old test) to legacy/. Active engine + GUI are fully standalone. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 4 + README.md | 22 +- legacy/README.md | 4 + .../backend_fastapi}/api/__init__.py | 0 .../backend_fastapi}/api/v1/__init__.py | 0 .../backend_fastapi}/api/v1/agent.py | 0 .../backend_fastapi}/api/v1/agent_tasks.py | 0 .../backend_fastapi}/api/v1/cli_agent.py | 0 .../backend_fastapi}/api/v1/dashboard.py | 0 .../backend_fastapi}/api/v1/full_ia.py | 0 .../backend_fastapi}/api/v1/knowledge.py | 0 .../backend_fastapi}/api/v1/mcp.py | 0 .../backend_fastapi}/api/v1/prompts.py | 0 .../backend_fastapi}/api/v1/providers.py | 0 .../backend_fastapi}/api/v1/reports.py | 0 .../backend_fastapi}/api/v1/sandbox.py | 0 .../backend_fastapi}/api/v1/scans.py | 0 .../backend_fastapi}/api/v1/scheduler.py | 0 .../backend_fastapi}/api/v1/settings.py | 0 .../backend_fastapi}/api/v1/targets.py | 0 .../backend_fastapi}/api/v1/terminal.py | 0 .../backend_fastapi}/api/v1/vuln_lab.py | 0 .../api/v1/vulnerabilities.py | 0 .../backend_fastapi}/api/websocket.py | 0 {backend => legacy/backend_fastapi}/config.py | 0 .../backend_fastapi}/core/__init__.py | 0 .../core/access_control_learner.py | 0 .../backend_fastapi}/core/adaptive_learner.py | 0 .../backend_fastapi}/core/agent_base.py | 0 .../backend_fastapi}/core/agent_memory.py | 0 .../core/agent_orchestrator.py | 0 .../backend_fastapi}/core/agent_tasks.py | 0 .../backend_fastapi}/core/ai_pentest_agent.py | 0 .../core/ai_prompt_processor.py | 0 .../backend_fastapi}/core/auth_manager.py | 0 .../backend_fastapi}/core/autonomous_agent.py | 0 .../core/autonomous_scanner.py | 0 .../backend_fastapi}/core/banner_analyzer.py | 0 .../backend_fastapi}/core/chain_engine.py | 0 .../core/checkpoint_manager.py | 0 .../backend_fastapi}/core/cli_agent_runner.py | 0 .../core/cli_instructions_builder.py | 0 .../core/cli_output_parser.py | 0 .../core/confidence_scorer.py | 0 .../backend_fastapi}/core/cve_hunter.py | 0 .../backend_fastapi}/core/deep_recon.py | 0 .../core/endpoint_classifier.py | 0 .../core/execution_history.py | 0 .../core/exploit_generator.py | 0 .../core/knowledge_processor.py | 0 .../backend_fastapi}/core/md_agent.py | 0 .../core/methodology_loader.py | 0 .../backend_fastapi}/core/negative_control.py | 0 .../core/notification_manager.py | 0 .../backend_fastapi}/core/param_analyzer.py | 0 .../backend_fastapi}/core/payload_mutator.py | 0 .../backend_fastapi}/core/poc_generator.py | 0 .../backend_fastapi}/core/poc_validator.py | 0 .../core/prompt_engine/__init__.py | 0 .../core/prompt_engine/parser.py | 0 .../core/proof_of_execution.py | 0 .../backend_fastapi}/core/rag/__init__.py | 0 .../backend_fastapi}/core/rag/engine.py | 0 .../backend_fastapi}/core/rag/few_shot.py | 0 .../core/rag/reasoning_memory.py | 0 .../core/rag/reasoning_templates.py | 0 .../backend_fastapi}/core/rag/vectorstore.py | 0 .../backend_fastapi}/core/reasoning_engine.py | 0 .../core/recon_integration.py | 0 .../core/report_engine/__init__.py | 0 .../core/report_engine/generator.py | 0 .../backend_fastapi}/core/report_generator.py | 0 .../backend_fastapi}/core/request_engine.py | 0 .../backend_fastapi}/core/request_repeater.py | 0 .../backend_fastapi}/core/researcher_agent.py | 0 .../core/response_verifier.py | 0 .../backend_fastapi}/core/site_analyzer.py | 0 .../core/smart_router/__init__.py | 0 .../core/smart_router/provider_registry.py | 0 .../core/smart_router/router.py | 0 .../core/smart_router/token_extractor.py | 0 .../core/smart_router/token_refresher.py | 0 .../core/specialist_agents.py | 0 .../backend_fastapi}/core/strategy_adapter.py | 0 .../backend_fastapi}/core/task_library.py | 0 .../backend_fastapi}/core/token_budget.py | 0 .../backend_fastapi}/core/tool_executor.py | 0 .../backend_fastapi}/core/validation_judge.py | 0 .../core/vuln_engine/__init__.py | 0 .../core/vuln_engine/ai_prompts.py | 0 .../core/vuln_engine/engine.py | 0 .../core/vuln_engine/payload_generator.py | 0 .../core/vuln_engine/pentest_playbook.py | 0 .../core/vuln_engine/registry.py | 0 .../core/vuln_engine/system_prompts.py | 0 .../core/vuln_engine/testers/__init__.py | 0 .../vuln_engine/testers/advanced_injection.py | 0 .../core/vuln_engine/testers/auth.py | 0 .../core/vuln_engine/testers/authorization.py | 0 .../core/vuln_engine/testers/base_tester.py | 0 .../core/vuln_engine/testers/client_side.py | 0 .../core/vuln_engine/testers/cloud_supply.py | 0 .../core/vuln_engine/testers/data_exposure.py | 0 .../core/vuln_engine/testers/file_access.py | 0 .../vuln_engine/testers/infrastructure.py | 0 .../core/vuln_engine/testers/injection.py | 0 .../core/vuln_engine/testers/logic.py | 0 .../vuln_engine/testers/request_forgery.py | 0 .../core/vuln_orchestrator.py | 0 .../backend_fastapi}/core/vuln_type_agent.py | 0 .../backend_fastapi}/core/waf_detector.py | 0 .../core/xss_context_analyzer.py | 0 .../backend_fastapi}/core/xss_validator.py | 0 .../backend_fastapi}/db/__init__.py | 0 .../backend_fastapi}/db/database.py | 0 {backend => legacy/backend_fastapi}/main.py | 0 .../001_add_dashboard_integration.sql | 0 .../backend_fastapi}/migrations/__init__.py | 0 .../migrations/run_migrations.py | 0 .../backend_fastapi}/models/__init__.py | 0 .../backend_fastapi}/models/agent_task.py | 0 .../backend_fastapi}/models/endpoint.py | 0 .../backend_fastapi}/models/prompt.py | 0 .../backend_fastapi}/models/report.py | 0 .../backend_fastapi}/models/scan.py | 0 .../backend_fastapi}/models/target.py | 0 .../backend_fastapi}/models/vuln_lab.py | 0 .../backend_fastapi}/models/vulnerability.py | 0 .../backend_fastapi}/requirements.txt | 0 .../backend_fastapi}/schemas/__init__.py | 0 .../backend_fastapi}/schemas/agent_task.py | 0 .../backend_fastapi}/schemas/prompt.py | 0 .../backend_fastapi}/schemas/report.py | 0 .../backend_fastapi}/schemas/scan.py | 0 .../backend_fastapi}/schemas/target.py | 0 .../backend_fastapi}/schemas/vulnerability.py | 0 .../backend_fastapi}/services/__init__.py | 0 .../services/report_service.py | 0 .../backend_fastapi}/services/scan_service.py | 0 {core => legacy/core}/__init__.py | 0 {core => legacy/core}/browser_validator.py | 0 {core => legacy/core}/container_pool.py | 0 {core => legacy/core}/context_builder.py | 0 {core => legacy/core}/kali_sandbox.py | 0 {core => legacy/core}/knowledge_augmentor.py | 0 {core => legacy/core}/llm_manager.py | 0 {core => legacy/core}/mcp_client.py | 0 {core => legacy/core}/mcp_server.py | 0 {core => legacy/core}/model_router.py | 0 {core => legacy/core}/pentest_executor.py | 0 {core => legacy/core}/report_generator.py | 0 {core => legacy/core}/sandbox_manager.py | 0 {core => legacy/core}/scheduler.py | 0 {core => legacy/core}/tool_installer.py | 0 {core => legacy/core}/tool_registry.py | 0 .../frontend_react}/index.html | 0 .../frontend_react}/package-lock.json | 0 .../frontend_react}/package.json | 0 .../frontend_react}/postcss.config.js | 0 .../frontend_react}/public/favicon.svg | 0 .../frontend_react}/src/App.tsx | 0 .../src/components/VulnAgentGrid.tsx | 0 .../src/components/common/Badge.tsx | 0 .../src/components/common/Button.tsx | 0 .../src/components/common/Card.tsx | 0 .../src/components/common/Input.tsx | 0 .../src/components/common/Textarea.tsx | 0 .../src/components/layout/Header.tsx | 0 .../src/components/layout/Layout.tsx | 0 .../src/components/layout/Sidebar.tsx | 0 .../frontend_react}/src/main.tsx | 0 .../src/pages/AgentStatusPage.tsx | 0 .../src/pages/AutoPentestPage.tsx | 0 .../src/pages/FullIATestingPage.tsx | 0 .../frontend_react}/src/pages/HomePage.tsx | 0 .../src/pages/KnowledgePage.tsx | 0 .../src/pages/MCPManagementPage.tsx | 0 .../frontend_react}/src/pages/NewScanPage.tsx | 0 .../src/pages/ProvidersPage.tsx | 0 .../src/pages/RealtimeTaskPage.tsx | 0 .../src/pages/ReportViewPage.tsx | 0 .../frontend_react}/src/pages/ReportsPage.tsx | 0 .../src/pages/SandboxDashboardPage.tsx | 0 .../src/pages/ScanDetailsPage.tsx | 0 .../src/pages/SchedulerPage.tsx | 0 .../src/pages/SettingsPage.tsx | 0 .../src/pages/TaskLibraryPage.tsx | 0 .../src/pages/TerminalAgentPage.tsx | 0 .../frontend_react}/src/pages/VulnLabPage.tsx | 0 .../frontend_react}/src/services/api.ts | 0 .../frontend_react}/src/services/websocket.ts | 0 .../frontend_react}/src/store/index.ts | 0 .../frontend_react}/src/styles/globals.css | 0 .../frontend_react}/src/types/index.ts | 0 .../frontend_react}/tailwind.config.js | 0 .../frontend_react}/tsconfig.json | 0 .../frontend_react}/tsconfig.node.json | 0 .../frontend_react}/vite.config.ts | 0 test_agent_run.py => legacy/test_agent_run.py | 0 neurosploit_agent/backends.py | 16 +- neurosploit_agent/models.py | 69 ++- neurosploit_agent/orchestrator.py | 47 +- neurosploit_agent/report.py | 152 ++++++ webgui/index.html | 452 ++++++++++++------ webgui/server.py | 242 ++++++++-- 205 files changed, 809 insertions(+), 199 deletions(-) rename {backend => legacy/backend_fastapi}/api/__init__.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/__init__.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/agent.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/agent_tasks.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/cli_agent.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/dashboard.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/full_ia.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/knowledge.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/mcp.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/prompts.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/providers.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/reports.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/sandbox.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/scans.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/scheduler.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/settings.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/targets.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/terminal.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/vuln_lab.py (100%) rename {backend => legacy/backend_fastapi}/api/v1/vulnerabilities.py (100%) rename {backend => legacy/backend_fastapi}/api/websocket.py (100%) rename {backend => legacy/backend_fastapi}/config.py (100%) rename {backend => legacy/backend_fastapi}/core/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/access_control_learner.py (100%) rename {backend => legacy/backend_fastapi}/core/adaptive_learner.py (100%) rename {backend => legacy/backend_fastapi}/core/agent_base.py (100%) rename {backend => legacy/backend_fastapi}/core/agent_memory.py (100%) rename {backend => legacy/backend_fastapi}/core/agent_orchestrator.py (100%) rename {backend => legacy/backend_fastapi}/core/agent_tasks.py (100%) rename {backend => legacy/backend_fastapi}/core/ai_pentest_agent.py (100%) rename {backend => legacy/backend_fastapi}/core/ai_prompt_processor.py (100%) rename {backend => legacy/backend_fastapi}/core/auth_manager.py (100%) rename {backend => legacy/backend_fastapi}/core/autonomous_agent.py (100%) rename {backend => legacy/backend_fastapi}/core/autonomous_scanner.py (100%) rename {backend => legacy/backend_fastapi}/core/banner_analyzer.py (100%) rename {backend => legacy/backend_fastapi}/core/chain_engine.py (100%) rename {backend => legacy/backend_fastapi}/core/checkpoint_manager.py (100%) rename {backend => legacy/backend_fastapi}/core/cli_agent_runner.py (100%) rename {backend => legacy/backend_fastapi}/core/cli_instructions_builder.py (100%) rename {backend => legacy/backend_fastapi}/core/cli_output_parser.py (100%) rename {backend => legacy/backend_fastapi}/core/confidence_scorer.py (100%) rename {backend => legacy/backend_fastapi}/core/cve_hunter.py (100%) rename {backend => legacy/backend_fastapi}/core/deep_recon.py (100%) rename {backend => legacy/backend_fastapi}/core/endpoint_classifier.py (100%) rename {backend => legacy/backend_fastapi}/core/execution_history.py (100%) rename {backend => legacy/backend_fastapi}/core/exploit_generator.py (100%) rename {backend => legacy/backend_fastapi}/core/knowledge_processor.py (100%) rename {backend => legacy/backend_fastapi}/core/md_agent.py (100%) rename {backend => legacy/backend_fastapi}/core/methodology_loader.py (100%) rename {backend => legacy/backend_fastapi}/core/negative_control.py (100%) rename {backend => legacy/backend_fastapi}/core/notification_manager.py (100%) rename {backend => legacy/backend_fastapi}/core/param_analyzer.py (100%) rename {backend => legacy/backend_fastapi}/core/payload_mutator.py (100%) rename {backend => legacy/backend_fastapi}/core/poc_generator.py (100%) rename {backend => legacy/backend_fastapi}/core/poc_validator.py (100%) rename {backend => legacy/backend_fastapi}/core/prompt_engine/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/prompt_engine/parser.py (100%) rename {backend => legacy/backend_fastapi}/core/proof_of_execution.py (100%) rename {backend => legacy/backend_fastapi}/core/rag/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/rag/engine.py (100%) rename {backend => legacy/backend_fastapi}/core/rag/few_shot.py (100%) rename {backend => legacy/backend_fastapi}/core/rag/reasoning_memory.py (100%) rename {backend => legacy/backend_fastapi}/core/rag/reasoning_templates.py (100%) rename {backend => legacy/backend_fastapi}/core/rag/vectorstore.py (100%) rename {backend => legacy/backend_fastapi}/core/reasoning_engine.py (100%) rename {backend => legacy/backend_fastapi}/core/recon_integration.py (100%) rename {backend => legacy/backend_fastapi}/core/report_engine/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/report_engine/generator.py (100%) rename {backend => legacy/backend_fastapi}/core/report_generator.py (100%) rename {backend => legacy/backend_fastapi}/core/request_engine.py (100%) rename {backend => legacy/backend_fastapi}/core/request_repeater.py (100%) rename {backend => legacy/backend_fastapi}/core/researcher_agent.py (100%) rename {backend => legacy/backend_fastapi}/core/response_verifier.py (100%) rename {backend => legacy/backend_fastapi}/core/site_analyzer.py (100%) rename {backend => legacy/backend_fastapi}/core/smart_router/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/smart_router/provider_registry.py (100%) rename {backend => legacy/backend_fastapi}/core/smart_router/router.py (100%) rename {backend => legacy/backend_fastapi}/core/smart_router/token_extractor.py (100%) rename {backend => legacy/backend_fastapi}/core/smart_router/token_refresher.py (100%) rename {backend => legacy/backend_fastapi}/core/specialist_agents.py (100%) rename {backend => legacy/backend_fastapi}/core/strategy_adapter.py (100%) rename {backend => legacy/backend_fastapi}/core/task_library.py (100%) rename {backend => legacy/backend_fastapi}/core/token_budget.py (100%) rename {backend => legacy/backend_fastapi}/core/tool_executor.py (100%) rename {backend => legacy/backend_fastapi}/core/validation_judge.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/ai_prompts.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/engine.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/payload_generator.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/pentest_playbook.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/registry.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/system_prompts.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/__init__.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/advanced_injection.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/auth.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/authorization.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/base_tester.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/client_side.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/cloud_supply.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/data_exposure.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/file_access.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/infrastructure.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/injection.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/logic.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_engine/testers/request_forgery.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_orchestrator.py (100%) rename {backend => legacy/backend_fastapi}/core/vuln_type_agent.py (100%) rename {backend => legacy/backend_fastapi}/core/waf_detector.py (100%) rename {backend => legacy/backend_fastapi}/core/xss_context_analyzer.py (100%) rename {backend => legacy/backend_fastapi}/core/xss_validator.py (100%) rename {backend => legacy/backend_fastapi}/db/__init__.py (100%) rename {backend => legacy/backend_fastapi}/db/database.py (100%) rename {backend => legacy/backend_fastapi}/main.py (100%) rename {backend => legacy/backend_fastapi}/migrations/001_add_dashboard_integration.sql (100%) rename {backend => legacy/backend_fastapi}/migrations/__init__.py (100%) rename {backend => legacy/backend_fastapi}/migrations/run_migrations.py (100%) rename {backend => legacy/backend_fastapi}/models/__init__.py (100%) rename {backend => legacy/backend_fastapi}/models/agent_task.py (100%) rename {backend => legacy/backend_fastapi}/models/endpoint.py (100%) rename {backend => legacy/backend_fastapi}/models/prompt.py (100%) rename {backend => legacy/backend_fastapi}/models/report.py (100%) rename {backend => legacy/backend_fastapi}/models/scan.py (100%) rename {backend => legacy/backend_fastapi}/models/target.py (100%) rename {backend => legacy/backend_fastapi}/models/vuln_lab.py (100%) rename {backend => legacy/backend_fastapi}/models/vulnerability.py (100%) rename {backend => legacy/backend_fastapi}/requirements.txt (100%) rename {backend => legacy/backend_fastapi}/schemas/__init__.py (100%) rename {backend => legacy/backend_fastapi}/schemas/agent_task.py (100%) rename {backend => legacy/backend_fastapi}/schemas/prompt.py (100%) rename {backend => legacy/backend_fastapi}/schemas/report.py (100%) rename {backend => legacy/backend_fastapi}/schemas/scan.py (100%) rename {backend => legacy/backend_fastapi}/schemas/target.py (100%) rename {backend => legacy/backend_fastapi}/schemas/vulnerability.py (100%) rename {backend => legacy/backend_fastapi}/services/__init__.py (100%) rename {backend => legacy/backend_fastapi}/services/report_service.py (100%) rename {backend => legacy/backend_fastapi}/services/scan_service.py (100%) rename {core => legacy/core}/__init__.py (100%) rename {core => legacy/core}/browser_validator.py (100%) rename {core => legacy/core}/container_pool.py (100%) rename {core => legacy/core}/context_builder.py (100%) rename {core => legacy/core}/kali_sandbox.py (100%) rename {core => legacy/core}/knowledge_augmentor.py (100%) rename {core => legacy/core}/llm_manager.py (100%) rename {core => legacy/core}/mcp_client.py (100%) rename {core => legacy/core}/mcp_server.py (100%) rename {core => legacy/core}/model_router.py (100%) rename {core => legacy/core}/pentest_executor.py (100%) rename {core => legacy/core}/report_generator.py (100%) rename {core => legacy/core}/sandbox_manager.py (100%) rename {core => legacy/core}/scheduler.py (100%) rename {core => legacy/core}/tool_installer.py (100%) rename {core => legacy/core}/tool_registry.py (100%) rename {frontend => legacy/frontend_react}/index.html (100%) rename {frontend => legacy/frontend_react}/package-lock.json (100%) rename {frontend => legacy/frontend_react}/package.json (100%) rename {frontend => legacy/frontend_react}/postcss.config.js (100%) rename {frontend => legacy/frontend_react}/public/favicon.svg (100%) rename {frontend => legacy/frontend_react}/src/App.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/VulnAgentGrid.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/common/Badge.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/common/Button.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/common/Card.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/common/Input.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/common/Textarea.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/layout/Header.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/layout/Layout.tsx (100%) rename {frontend => legacy/frontend_react}/src/components/layout/Sidebar.tsx (100%) rename {frontend => legacy/frontend_react}/src/main.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/AgentStatusPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/AutoPentestPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/FullIATestingPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/HomePage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/KnowledgePage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/MCPManagementPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/NewScanPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/ProvidersPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/RealtimeTaskPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/ReportViewPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/ReportsPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/SandboxDashboardPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/ScanDetailsPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/SchedulerPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/SettingsPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/TaskLibraryPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/TerminalAgentPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/pages/VulnLabPage.tsx (100%) rename {frontend => legacy/frontend_react}/src/services/api.ts (100%) rename {frontend => legacy/frontend_react}/src/services/websocket.ts (100%) rename {frontend => legacy/frontend_react}/src/store/index.ts (100%) rename {frontend => legacy/frontend_react}/src/styles/globals.css (100%) rename {frontend => legacy/frontend_react}/src/types/index.ts (100%) rename {frontend => legacy/frontend_react}/tailwind.config.js (100%) rename {frontend => legacy/frontend_react}/tsconfig.json (100%) rename {frontend => legacy/frontend_react}/tsconfig.node.json (100%) rename {frontend => legacy/frontend_react}/vite.config.ts (100%) rename test_agent_run.py => legacy/test_agent_run.py (100%) create mode 100644 neurosploit_agent/report.py diff --git a/.gitignore b/.gitignore index 4d728f6..cf122ae 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,7 @@ data/rl_state.json neurosploit_gui_*.png neurosploit_demo_*.png logs/webgui.log + +# generated reports +reports/report.* +reports/*.pdf diff --git a/README.md b/README.md index 25c27e7..c7128c2 100755 --- a/README.md +++ b/README.md @@ -114,18 +114,28 @@ data-driven builder, `scripts/build_agents.py`). It is picked up automatically. Outputs land in `results//findings.json` and `reports/`, and the RL state updates in `data/rl_state.json`. -### Minimalist web GUI +### Web dashboard -A zero-dependency (Python stdlib only) web front-end exposes just the essential -options — target URL, backend, model, collaborator, and the RL / Playwright-MCP -toggles — and launches an engagement with a live progress console: +A zero-dependency (Python stdlib only) dashboard — no npm, no build step: ```bash python3 webgui/server.py # → http://127.0.0.1:8787 ``` -No npm, no build step. It calls `neurosploit_agent` directly. (The previous heavy -React app remains under `frontend/` but is no longer the primary interface.) +Tabs: +- **Run** — multi-target input, backend + provider + model pickers (40 models + across CLI and API providers), verbosity, RL/MCP toggles, a live execution + console (shows the exact backend command and per-task activity), and findings + with screenshots. +- **Agents** — browse all 213 agents and **add new `.md` agents** from the UI; + the main orchestrator picks them up on the next run. +- **Insights** — interactive chart of RL agent weights + findings by severity. +- **Reports** — download/preview the **PDF + HTML** reports (Typst engine). +- **Settings · API** — execution mode (CLI vs API), per-provider API keys, + orchestrator selection, default verbosity. + +It calls `neurosploit_agent` directly. The previous React app and FastAPI backend +were retired to `legacy/` (`frontend_react/`, `backend_fastapi/`). ### Backends diff --git a/legacy/README.md b/legacy/README.md index bfed0b1..e298dea 100644 --- a/legacy/README.md +++ b/legacy/README.md @@ -11,6 +11,10 @@ Kept for reference and migration only — **not** used by the v3.3.0 engine. | `neurosploit_legacy.py` | The 2,500-line monolithic CLI/orchestrator (`NeuroSploitv2`) | | `agents_python/` | Hand-coded Python agent classes (web/exploitation/lateral/privesc/persistence/recon) | | `custom_agents/` | Example custom Python agent | +| `core/` | Old orchestration support (llm_manager, sandbox, report_generator, …) | +| `backend_fastapi/` | Old FastAPI backend — replaced by `webgui/server.py` (stdlib) | +| `frontend_react/` | Old React/Vite dashboard — replaced by the minimalist `webgui/` | +| `test_agent_run.py` | Test harness for the old Python agents | ## What replaced it diff --git a/backend/api/__init__.py b/legacy/backend_fastapi/api/__init__.py similarity index 100% rename from backend/api/__init__.py rename to legacy/backend_fastapi/api/__init__.py diff --git a/backend/api/v1/__init__.py b/legacy/backend_fastapi/api/v1/__init__.py similarity index 100% rename from backend/api/v1/__init__.py rename to legacy/backend_fastapi/api/v1/__init__.py diff --git a/backend/api/v1/agent.py b/legacy/backend_fastapi/api/v1/agent.py similarity index 100% rename from backend/api/v1/agent.py rename to legacy/backend_fastapi/api/v1/agent.py diff --git a/backend/api/v1/agent_tasks.py b/legacy/backend_fastapi/api/v1/agent_tasks.py similarity index 100% rename from backend/api/v1/agent_tasks.py rename to legacy/backend_fastapi/api/v1/agent_tasks.py diff --git a/backend/api/v1/cli_agent.py b/legacy/backend_fastapi/api/v1/cli_agent.py similarity index 100% rename from backend/api/v1/cli_agent.py rename to legacy/backend_fastapi/api/v1/cli_agent.py diff --git a/backend/api/v1/dashboard.py b/legacy/backend_fastapi/api/v1/dashboard.py similarity index 100% rename from backend/api/v1/dashboard.py rename to legacy/backend_fastapi/api/v1/dashboard.py diff --git a/backend/api/v1/full_ia.py b/legacy/backend_fastapi/api/v1/full_ia.py similarity index 100% rename from backend/api/v1/full_ia.py rename to legacy/backend_fastapi/api/v1/full_ia.py diff --git a/backend/api/v1/knowledge.py b/legacy/backend_fastapi/api/v1/knowledge.py similarity index 100% rename from backend/api/v1/knowledge.py rename to legacy/backend_fastapi/api/v1/knowledge.py diff --git a/backend/api/v1/mcp.py b/legacy/backend_fastapi/api/v1/mcp.py similarity index 100% rename from backend/api/v1/mcp.py rename to legacy/backend_fastapi/api/v1/mcp.py diff --git a/backend/api/v1/prompts.py b/legacy/backend_fastapi/api/v1/prompts.py similarity index 100% rename from backend/api/v1/prompts.py rename to legacy/backend_fastapi/api/v1/prompts.py diff --git a/backend/api/v1/providers.py b/legacy/backend_fastapi/api/v1/providers.py similarity index 100% rename from backend/api/v1/providers.py rename to legacy/backend_fastapi/api/v1/providers.py diff --git a/backend/api/v1/reports.py b/legacy/backend_fastapi/api/v1/reports.py similarity index 100% rename from backend/api/v1/reports.py rename to legacy/backend_fastapi/api/v1/reports.py diff --git a/backend/api/v1/sandbox.py b/legacy/backend_fastapi/api/v1/sandbox.py similarity index 100% rename from backend/api/v1/sandbox.py rename to legacy/backend_fastapi/api/v1/sandbox.py diff --git a/backend/api/v1/scans.py b/legacy/backend_fastapi/api/v1/scans.py similarity index 100% rename from backend/api/v1/scans.py rename to legacy/backend_fastapi/api/v1/scans.py diff --git a/backend/api/v1/scheduler.py b/legacy/backend_fastapi/api/v1/scheduler.py similarity index 100% rename from backend/api/v1/scheduler.py rename to legacy/backend_fastapi/api/v1/scheduler.py diff --git a/backend/api/v1/settings.py b/legacy/backend_fastapi/api/v1/settings.py similarity index 100% rename from backend/api/v1/settings.py rename to legacy/backend_fastapi/api/v1/settings.py diff --git a/backend/api/v1/targets.py b/legacy/backend_fastapi/api/v1/targets.py similarity index 100% rename from backend/api/v1/targets.py rename to legacy/backend_fastapi/api/v1/targets.py diff --git a/backend/api/v1/terminal.py b/legacy/backend_fastapi/api/v1/terminal.py similarity index 100% rename from backend/api/v1/terminal.py rename to legacy/backend_fastapi/api/v1/terminal.py diff --git a/backend/api/v1/vuln_lab.py b/legacy/backend_fastapi/api/v1/vuln_lab.py similarity index 100% rename from backend/api/v1/vuln_lab.py rename to legacy/backend_fastapi/api/v1/vuln_lab.py diff --git a/backend/api/v1/vulnerabilities.py b/legacy/backend_fastapi/api/v1/vulnerabilities.py similarity index 100% rename from backend/api/v1/vulnerabilities.py rename to legacy/backend_fastapi/api/v1/vulnerabilities.py diff --git a/backend/api/websocket.py b/legacy/backend_fastapi/api/websocket.py similarity index 100% rename from backend/api/websocket.py rename to legacy/backend_fastapi/api/websocket.py diff --git a/backend/config.py b/legacy/backend_fastapi/config.py similarity index 100% rename from backend/config.py rename to legacy/backend_fastapi/config.py diff --git a/backend/core/__init__.py b/legacy/backend_fastapi/core/__init__.py similarity index 100% rename from backend/core/__init__.py rename to legacy/backend_fastapi/core/__init__.py diff --git a/backend/core/access_control_learner.py b/legacy/backend_fastapi/core/access_control_learner.py similarity index 100% rename from backend/core/access_control_learner.py rename to legacy/backend_fastapi/core/access_control_learner.py diff --git a/backend/core/adaptive_learner.py b/legacy/backend_fastapi/core/adaptive_learner.py similarity index 100% rename from backend/core/adaptive_learner.py rename to legacy/backend_fastapi/core/adaptive_learner.py diff --git a/backend/core/agent_base.py b/legacy/backend_fastapi/core/agent_base.py similarity index 100% rename from backend/core/agent_base.py rename to legacy/backend_fastapi/core/agent_base.py diff --git a/backend/core/agent_memory.py b/legacy/backend_fastapi/core/agent_memory.py similarity index 100% rename from backend/core/agent_memory.py rename to legacy/backend_fastapi/core/agent_memory.py diff --git a/backend/core/agent_orchestrator.py b/legacy/backend_fastapi/core/agent_orchestrator.py similarity index 100% rename from backend/core/agent_orchestrator.py rename to legacy/backend_fastapi/core/agent_orchestrator.py diff --git a/backend/core/agent_tasks.py b/legacy/backend_fastapi/core/agent_tasks.py similarity index 100% rename from backend/core/agent_tasks.py rename to legacy/backend_fastapi/core/agent_tasks.py diff --git a/backend/core/ai_pentest_agent.py b/legacy/backend_fastapi/core/ai_pentest_agent.py similarity index 100% rename from backend/core/ai_pentest_agent.py rename to legacy/backend_fastapi/core/ai_pentest_agent.py diff --git a/backend/core/ai_prompt_processor.py b/legacy/backend_fastapi/core/ai_prompt_processor.py similarity index 100% rename from backend/core/ai_prompt_processor.py rename to legacy/backend_fastapi/core/ai_prompt_processor.py diff --git a/backend/core/auth_manager.py b/legacy/backend_fastapi/core/auth_manager.py similarity index 100% rename from backend/core/auth_manager.py rename to legacy/backend_fastapi/core/auth_manager.py diff --git a/backend/core/autonomous_agent.py b/legacy/backend_fastapi/core/autonomous_agent.py similarity index 100% rename from backend/core/autonomous_agent.py rename to legacy/backend_fastapi/core/autonomous_agent.py diff --git a/backend/core/autonomous_scanner.py b/legacy/backend_fastapi/core/autonomous_scanner.py similarity index 100% rename from backend/core/autonomous_scanner.py rename to legacy/backend_fastapi/core/autonomous_scanner.py diff --git a/backend/core/banner_analyzer.py b/legacy/backend_fastapi/core/banner_analyzer.py similarity index 100% rename from backend/core/banner_analyzer.py rename to legacy/backend_fastapi/core/banner_analyzer.py diff --git a/backend/core/chain_engine.py b/legacy/backend_fastapi/core/chain_engine.py similarity index 100% rename from backend/core/chain_engine.py rename to legacy/backend_fastapi/core/chain_engine.py diff --git a/backend/core/checkpoint_manager.py b/legacy/backend_fastapi/core/checkpoint_manager.py similarity index 100% rename from backend/core/checkpoint_manager.py rename to legacy/backend_fastapi/core/checkpoint_manager.py diff --git a/backend/core/cli_agent_runner.py b/legacy/backend_fastapi/core/cli_agent_runner.py similarity index 100% rename from backend/core/cli_agent_runner.py rename to legacy/backend_fastapi/core/cli_agent_runner.py diff --git a/backend/core/cli_instructions_builder.py b/legacy/backend_fastapi/core/cli_instructions_builder.py similarity index 100% rename from backend/core/cli_instructions_builder.py rename to legacy/backend_fastapi/core/cli_instructions_builder.py diff --git a/backend/core/cli_output_parser.py b/legacy/backend_fastapi/core/cli_output_parser.py similarity index 100% rename from backend/core/cli_output_parser.py rename to legacy/backend_fastapi/core/cli_output_parser.py diff --git a/backend/core/confidence_scorer.py b/legacy/backend_fastapi/core/confidence_scorer.py similarity index 100% rename from backend/core/confidence_scorer.py rename to legacy/backend_fastapi/core/confidence_scorer.py diff --git a/backend/core/cve_hunter.py b/legacy/backend_fastapi/core/cve_hunter.py similarity index 100% rename from backend/core/cve_hunter.py rename to legacy/backend_fastapi/core/cve_hunter.py diff --git a/backend/core/deep_recon.py b/legacy/backend_fastapi/core/deep_recon.py similarity index 100% rename from backend/core/deep_recon.py rename to legacy/backend_fastapi/core/deep_recon.py diff --git a/backend/core/endpoint_classifier.py b/legacy/backend_fastapi/core/endpoint_classifier.py similarity index 100% rename from backend/core/endpoint_classifier.py rename to legacy/backend_fastapi/core/endpoint_classifier.py diff --git a/backend/core/execution_history.py b/legacy/backend_fastapi/core/execution_history.py similarity index 100% rename from backend/core/execution_history.py rename to legacy/backend_fastapi/core/execution_history.py diff --git a/backend/core/exploit_generator.py b/legacy/backend_fastapi/core/exploit_generator.py similarity index 100% rename from backend/core/exploit_generator.py rename to legacy/backend_fastapi/core/exploit_generator.py diff --git a/backend/core/knowledge_processor.py b/legacy/backend_fastapi/core/knowledge_processor.py similarity index 100% rename from backend/core/knowledge_processor.py rename to legacy/backend_fastapi/core/knowledge_processor.py diff --git a/backend/core/md_agent.py b/legacy/backend_fastapi/core/md_agent.py similarity index 100% rename from backend/core/md_agent.py rename to legacy/backend_fastapi/core/md_agent.py diff --git a/backend/core/methodology_loader.py b/legacy/backend_fastapi/core/methodology_loader.py similarity index 100% rename from backend/core/methodology_loader.py rename to legacy/backend_fastapi/core/methodology_loader.py diff --git a/backend/core/negative_control.py b/legacy/backend_fastapi/core/negative_control.py similarity index 100% rename from backend/core/negative_control.py rename to legacy/backend_fastapi/core/negative_control.py diff --git a/backend/core/notification_manager.py b/legacy/backend_fastapi/core/notification_manager.py similarity index 100% rename from backend/core/notification_manager.py rename to legacy/backend_fastapi/core/notification_manager.py diff --git a/backend/core/param_analyzer.py b/legacy/backend_fastapi/core/param_analyzer.py similarity index 100% rename from backend/core/param_analyzer.py rename to legacy/backend_fastapi/core/param_analyzer.py diff --git a/backend/core/payload_mutator.py b/legacy/backend_fastapi/core/payload_mutator.py similarity index 100% rename from backend/core/payload_mutator.py rename to legacy/backend_fastapi/core/payload_mutator.py diff --git a/backend/core/poc_generator.py b/legacy/backend_fastapi/core/poc_generator.py similarity index 100% rename from backend/core/poc_generator.py rename to legacy/backend_fastapi/core/poc_generator.py diff --git a/backend/core/poc_validator.py b/legacy/backend_fastapi/core/poc_validator.py similarity index 100% rename from backend/core/poc_validator.py rename to legacy/backend_fastapi/core/poc_validator.py diff --git a/backend/core/prompt_engine/__init__.py b/legacy/backend_fastapi/core/prompt_engine/__init__.py similarity index 100% rename from backend/core/prompt_engine/__init__.py rename to legacy/backend_fastapi/core/prompt_engine/__init__.py diff --git a/backend/core/prompt_engine/parser.py b/legacy/backend_fastapi/core/prompt_engine/parser.py similarity index 100% rename from backend/core/prompt_engine/parser.py rename to legacy/backend_fastapi/core/prompt_engine/parser.py diff --git a/backend/core/proof_of_execution.py b/legacy/backend_fastapi/core/proof_of_execution.py similarity index 100% rename from backend/core/proof_of_execution.py rename to legacy/backend_fastapi/core/proof_of_execution.py diff --git a/backend/core/rag/__init__.py b/legacy/backend_fastapi/core/rag/__init__.py similarity index 100% rename from backend/core/rag/__init__.py rename to legacy/backend_fastapi/core/rag/__init__.py diff --git a/backend/core/rag/engine.py b/legacy/backend_fastapi/core/rag/engine.py similarity index 100% rename from backend/core/rag/engine.py rename to legacy/backend_fastapi/core/rag/engine.py diff --git a/backend/core/rag/few_shot.py b/legacy/backend_fastapi/core/rag/few_shot.py similarity index 100% rename from backend/core/rag/few_shot.py rename to legacy/backend_fastapi/core/rag/few_shot.py diff --git a/backend/core/rag/reasoning_memory.py b/legacy/backend_fastapi/core/rag/reasoning_memory.py similarity index 100% rename from backend/core/rag/reasoning_memory.py rename to legacy/backend_fastapi/core/rag/reasoning_memory.py diff --git a/backend/core/rag/reasoning_templates.py b/legacy/backend_fastapi/core/rag/reasoning_templates.py similarity index 100% rename from backend/core/rag/reasoning_templates.py rename to legacy/backend_fastapi/core/rag/reasoning_templates.py diff --git a/backend/core/rag/vectorstore.py b/legacy/backend_fastapi/core/rag/vectorstore.py similarity index 100% rename from backend/core/rag/vectorstore.py rename to legacy/backend_fastapi/core/rag/vectorstore.py diff --git a/backend/core/reasoning_engine.py b/legacy/backend_fastapi/core/reasoning_engine.py similarity index 100% rename from backend/core/reasoning_engine.py rename to legacy/backend_fastapi/core/reasoning_engine.py diff --git a/backend/core/recon_integration.py b/legacy/backend_fastapi/core/recon_integration.py similarity index 100% rename from backend/core/recon_integration.py rename to legacy/backend_fastapi/core/recon_integration.py diff --git a/backend/core/report_engine/__init__.py b/legacy/backend_fastapi/core/report_engine/__init__.py similarity index 100% rename from backend/core/report_engine/__init__.py rename to legacy/backend_fastapi/core/report_engine/__init__.py diff --git a/backend/core/report_engine/generator.py b/legacy/backend_fastapi/core/report_engine/generator.py similarity index 100% rename from backend/core/report_engine/generator.py rename to legacy/backend_fastapi/core/report_engine/generator.py diff --git a/backend/core/report_generator.py b/legacy/backend_fastapi/core/report_generator.py similarity index 100% rename from backend/core/report_generator.py rename to legacy/backend_fastapi/core/report_generator.py diff --git a/backend/core/request_engine.py b/legacy/backend_fastapi/core/request_engine.py similarity index 100% rename from backend/core/request_engine.py rename to legacy/backend_fastapi/core/request_engine.py diff --git a/backend/core/request_repeater.py b/legacy/backend_fastapi/core/request_repeater.py similarity index 100% rename from backend/core/request_repeater.py rename to legacy/backend_fastapi/core/request_repeater.py diff --git a/backend/core/researcher_agent.py b/legacy/backend_fastapi/core/researcher_agent.py similarity index 100% rename from backend/core/researcher_agent.py rename to legacy/backend_fastapi/core/researcher_agent.py diff --git a/backend/core/response_verifier.py b/legacy/backend_fastapi/core/response_verifier.py similarity index 100% rename from backend/core/response_verifier.py rename to legacy/backend_fastapi/core/response_verifier.py diff --git a/backend/core/site_analyzer.py b/legacy/backend_fastapi/core/site_analyzer.py similarity index 100% rename from backend/core/site_analyzer.py rename to legacy/backend_fastapi/core/site_analyzer.py diff --git a/backend/core/smart_router/__init__.py b/legacy/backend_fastapi/core/smart_router/__init__.py similarity index 100% rename from backend/core/smart_router/__init__.py rename to legacy/backend_fastapi/core/smart_router/__init__.py diff --git a/backend/core/smart_router/provider_registry.py b/legacy/backend_fastapi/core/smart_router/provider_registry.py similarity index 100% rename from backend/core/smart_router/provider_registry.py rename to legacy/backend_fastapi/core/smart_router/provider_registry.py diff --git a/backend/core/smart_router/router.py b/legacy/backend_fastapi/core/smart_router/router.py similarity index 100% rename from backend/core/smart_router/router.py rename to legacy/backend_fastapi/core/smart_router/router.py diff --git a/backend/core/smart_router/token_extractor.py b/legacy/backend_fastapi/core/smart_router/token_extractor.py similarity index 100% rename from backend/core/smart_router/token_extractor.py rename to legacy/backend_fastapi/core/smart_router/token_extractor.py diff --git a/backend/core/smart_router/token_refresher.py b/legacy/backend_fastapi/core/smart_router/token_refresher.py similarity index 100% rename from backend/core/smart_router/token_refresher.py rename to legacy/backend_fastapi/core/smart_router/token_refresher.py diff --git a/backend/core/specialist_agents.py b/legacy/backend_fastapi/core/specialist_agents.py similarity index 100% rename from backend/core/specialist_agents.py rename to legacy/backend_fastapi/core/specialist_agents.py diff --git a/backend/core/strategy_adapter.py b/legacy/backend_fastapi/core/strategy_adapter.py similarity index 100% rename from backend/core/strategy_adapter.py rename to legacy/backend_fastapi/core/strategy_adapter.py diff --git a/backend/core/task_library.py b/legacy/backend_fastapi/core/task_library.py similarity index 100% rename from backend/core/task_library.py rename to legacy/backend_fastapi/core/task_library.py diff --git a/backend/core/token_budget.py b/legacy/backend_fastapi/core/token_budget.py similarity index 100% rename from backend/core/token_budget.py rename to legacy/backend_fastapi/core/token_budget.py diff --git a/backend/core/tool_executor.py b/legacy/backend_fastapi/core/tool_executor.py similarity index 100% rename from backend/core/tool_executor.py rename to legacy/backend_fastapi/core/tool_executor.py diff --git a/backend/core/validation_judge.py b/legacy/backend_fastapi/core/validation_judge.py similarity index 100% rename from backend/core/validation_judge.py rename to legacy/backend_fastapi/core/validation_judge.py diff --git a/backend/core/vuln_engine/__init__.py b/legacy/backend_fastapi/core/vuln_engine/__init__.py similarity index 100% rename from backend/core/vuln_engine/__init__.py rename to legacy/backend_fastapi/core/vuln_engine/__init__.py diff --git a/backend/core/vuln_engine/ai_prompts.py b/legacy/backend_fastapi/core/vuln_engine/ai_prompts.py similarity index 100% rename from backend/core/vuln_engine/ai_prompts.py rename to legacy/backend_fastapi/core/vuln_engine/ai_prompts.py diff --git a/backend/core/vuln_engine/engine.py b/legacy/backend_fastapi/core/vuln_engine/engine.py similarity index 100% rename from backend/core/vuln_engine/engine.py rename to legacy/backend_fastapi/core/vuln_engine/engine.py diff --git a/backend/core/vuln_engine/payload_generator.py b/legacy/backend_fastapi/core/vuln_engine/payload_generator.py similarity index 100% rename from backend/core/vuln_engine/payload_generator.py rename to legacy/backend_fastapi/core/vuln_engine/payload_generator.py diff --git a/backend/core/vuln_engine/pentest_playbook.py b/legacy/backend_fastapi/core/vuln_engine/pentest_playbook.py similarity index 100% rename from backend/core/vuln_engine/pentest_playbook.py rename to legacy/backend_fastapi/core/vuln_engine/pentest_playbook.py diff --git a/backend/core/vuln_engine/registry.py b/legacy/backend_fastapi/core/vuln_engine/registry.py similarity index 100% rename from backend/core/vuln_engine/registry.py rename to legacy/backend_fastapi/core/vuln_engine/registry.py diff --git a/backend/core/vuln_engine/system_prompts.py b/legacy/backend_fastapi/core/vuln_engine/system_prompts.py similarity index 100% rename from backend/core/vuln_engine/system_prompts.py rename to legacy/backend_fastapi/core/vuln_engine/system_prompts.py diff --git a/backend/core/vuln_engine/testers/__init__.py b/legacy/backend_fastapi/core/vuln_engine/testers/__init__.py similarity index 100% rename from backend/core/vuln_engine/testers/__init__.py rename to legacy/backend_fastapi/core/vuln_engine/testers/__init__.py diff --git a/backend/core/vuln_engine/testers/advanced_injection.py b/legacy/backend_fastapi/core/vuln_engine/testers/advanced_injection.py similarity index 100% rename from backend/core/vuln_engine/testers/advanced_injection.py rename to legacy/backend_fastapi/core/vuln_engine/testers/advanced_injection.py diff --git a/backend/core/vuln_engine/testers/auth.py b/legacy/backend_fastapi/core/vuln_engine/testers/auth.py similarity index 100% rename from backend/core/vuln_engine/testers/auth.py rename to legacy/backend_fastapi/core/vuln_engine/testers/auth.py diff --git a/backend/core/vuln_engine/testers/authorization.py b/legacy/backend_fastapi/core/vuln_engine/testers/authorization.py similarity index 100% rename from backend/core/vuln_engine/testers/authorization.py rename to legacy/backend_fastapi/core/vuln_engine/testers/authorization.py diff --git a/backend/core/vuln_engine/testers/base_tester.py b/legacy/backend_fastapi/core/vuln_engine/testers/base_tester.py similarity index 100% rename from backend/core/vuln_engine/testers/base_tester.py rename to legacy/backend_fastapi/core/vuln_engine/testers/base_tester.py diff --git a/backend/core/vuln_engine/testers/client_side.py b/legacy/backend_fastapi/core/vuln_engine/testers/client_side.py similarity index 100% rename from backend/core/vuln_engine/testers/client_side.py rename to legacy/backend_fastapi/core/vuln_engine/testers/client_side.py diff --git a/backend/core/vuln_engine/testers/cloud_supply.py b/legacy/backend_fastapi/core/vuln_engine/testers/cloud_supply.py similarity index 100% rename from backend/core/vuln_engine/testers/cloud_supply.py rename to legacy/backend_fastapi/core/vuln_engine/testers/cloud_supply.py diff --git a/backend/core/vuln_engine/testers/data_exposure.py b/legacy/backend_fastapi/core/vuln_engine/testers/data_exposure.py similarity index 100% rename from backend/core/vuln_engine/testers/data_exposure.py rename to legacy/backend_fastapi/core/vuln_engine/testers/data_exposure.py diff --git a/backend/core/vuln_engine/testers/file_access.py b/legacy/backend_fastapi/core/vuln_engine/testers/file_access.py similarity index 100% rename from backend/core/vuln_engine/testers/file_access.py rename to legacy/backend_fastapi/core/vuln_engine/testers/file_access.py diff --git a/backend/core/vuln_engine/testers/infrastructure.py b/legacy/backend_fastapi/core/vuln_engine/testers/infrastructure.py similarity index 100% rename from backend/core/vuln_engine/testers/infrastructure.py rename to legacy/backend_fastapi/core/vuln_engine/testers/infrastructure.py diff --git a/backend/core/vuln_engine/testers/injection.py b/legacy/backend_fastapi/core/vuln_engine/testers/injection.py similarity index 100% rename from backend/core/vuln_engine/testers/injection.py rename to legacy/backend_fastapi/core/vuln_engine/testers/injection.py diff --git a/backend/core/vuln_engine/testers/logic.py b/legacy/backend_fastapi/core/vuln_engine/testers/logic.py similarity index 100% rename from backend/core/vuln_engine/testers/logic.py rename to legacy/backend_fastapi/core/vuln_engine/testers/logic.py diff --git a/backend/core/vuln_engine/testers/request_forgery.py b/legacy/backend_fastapi/core/vuln_engine/testers/request_forgery.py similarity index 100% rename from backend/core/vuln_engine/testers/request_forgery.py rename to legacy/backend_fastapi/core/vuln_engine/testers/request_forgery.py diff --git a/backend/core/vuln_orchestrator.py b/legacy/backend_fastapi/core/vuln_orchestrator.py similarity index 100% rename from backend/core/vuln_orchestrator.py rename to legacy/backend_fastapi/core/vuln_orchestrator.py diff --git a/backend/core/vuln_type_agent.py b/legacy/backend_fastapi/core/vuln_type_agent.py similarity index 100% rename from backend/core/vuln_type_agent.py rename to legacy/backend_fastapi/core/vuln_type_agent.py diff --git a/backend/core/waf_detector.py b/legacy/backend_fastapi/core/waf_detector.py similarity index 100% rename from backend/core/waf_detector.py rename to legacy/backend_fastapi/core/waf_detector.py diff --git a/backend/core/xss_context_analyzer.py b/legacy/backend_fastapi/core/xss_context_analyzer.py similarity index 100% rename from backend/core/xss_context_analyzer.py rename to legacy/backend_fastapi/core/xss_context_analyzer.py diff --git a/backend/core/xss_validator.py b/legacy/backend_fastapi/core/xss_validator.py similarity index 100% rename from backend/core/xss_validator.py rename to legacy/backend_fastapi/core/xss_validator.py diff --git a/backend/db/__init__.py b/legacy/backend_fastapi/db/__init__.py similarity index 100% rename from backend/db/__init__.py rename to legacy/backend_fastapi/db/__init__.py diff --git a/backend/db/database.py b/legacy/backend_fastapi/db/database.py similarity index 100% rename from backend/db/database.py rename to legacy/backend_fastapi/db/database.py diff --git a/backend/main.py b/legacy/backend_fastapi/main.py similarity index 100% rename from backend/main.py rename to legacy/backend_fastapi/main.py diff --git a/backend/migrations/001_add_dashboard_integration.sql b/legacy/backend_fastapi/migrations/001_add_dashboard_integration.sql similarity index 100% rename from backend/migrations/001_add_dashboard_integration.sql rename to legacy/backend_fastapi/migrations/001_add_dashboard_integration.sql diff --git a/backend/migrations/__init__.py b/legacy/backend_fastapi/migrations/__init__.py similarity index 100% rename from backend/migrations/__init__.py rename to legacy/backend_fastapi/migrations/__init__.py diff --git a/backend/migrations/run_migrations.py b/legacy/backend_fastapi/migrations/run_migrations.py similarity index 100% rename from backend/migrations/run_migrations.py rename to legacy/backend_fastapi/migrations/run_migrations.py diff --git a/backend/models/__init__.py b/legacy/backend_fastapi/models/__init__.py similarity index 100% rename from backend/models/__init__.py rename to legacy/backend_fastapi/models/__init__.py diff --git a/backend/models/agent_task.py b/legacy/backend_fastapi/models/agent_task.py similarity index 100% rename from backend/models/agent_task.py rename to legacy/backend_fastapi/models/agent_task.py diff --git a/backend/models/endpoint.py b/legacy/backend_fastapi/models/endpoint.py similarity index 100% rename from backend/models/endpoint.py rename to legacy/backend_fastapi/models/endpoint.py diff --git a/backend/models/prompt.py b/legacy/backend_fastapi/models/prompt.py similarity index 100% rename from backend/models/prompt.py rename to legacy/backend_fastapi/models/prompt.py diff --git a/backend/models/report.py b/legacy/backend_fastapi/models/report.py similarity index 100% rename from backend/models/report.py rename to legacy/backend_fastapi/models/report.py diff --git a/backend/models/scan.py b/legacy/backend_fastapi/models/scan.py similarity index 100% rename from backend/models/scan.py rename to legacy/backend_fastapi/models/scan.py diff --git a/backend/models/target.py b/legacy/backend_fastapi/models/target.py similarity index 100% rename from backend/models/target.py rename to legacy/backend_fastapi/models/target.py diff --git a/backend/models/vuln_lab.py b/legacy/backend_fastapi/models/vuln_lab.py similarity index 100% rename from backend/models/vuln_lab.py rename to legacy/backend_fastapi/models/vuln_lab.py diff --git a/backend/models/vulnerability.py b/legacy/backend_fastapi/models/vulnerability.py similarity index 100% rename from backend/models/vulnerability.py rename to legacy/backend_fastapi/models/vulnerability.py diff --git a/backend/requirements.txt b/legacy/backend_fastapi/requirements.txt similarity index 100% rename from backend/requirements.txt rename to legacy/backend_fastapi/requirements.txt diff --git a/backend/schemas/__init__.py b/legacy/backend_fastapi/schemas/__init__.py similarity index 100% rename from backend/schemas/__init__.py rename to legacy/backend_fastapi/schemas/__init__.py diff --git a/backend/schemas/agent_task.py b/legacy/backend_fastapi/schemas/agent_task.py similarity index 100% rename from backend/schemas/agent_task.py rename to legacy/backend_fastapi/schemas/agent_task.py diff --git a/backend/schemas/prompt.py b/legacy/backend_fastapi/schemas/prompt.py similarity index 100% rename from backend/schemas/prompt.py rename to legacy/backend_fastapi/schemas/prompt.py diff --git a/backend/schemas/report.py b/legacy/backend_fastapi/schemas/report.py similarity index 100% rename from backend/schemas/report.py rename to legacy/backend_fastapi/schemas/report.py diff --git a/backend/schemas/scan.py b/legacy/backend_fastapi/schemas/scan.py similarity index 100% rename from backend/schemas/scan.py rename to legacy/backend_fastapi/schemas/scan.py diff --git a/backend/schemas/target.py b/legacy/backend_fastapi/schemas/target.py similarity index 100% rename from backend/schemas/target.py rename to legacy/backend_fastapi/schemas/target.py diff --git a/backend/schemas/vulnerability.py b/legacy/backend_fastapi/schemas/vulnerability.py similarity index 100% rename from backend/schemas/vulnerability.py rename to legacy/backend_fastapi/schemas/vulnerability.py diff --git a/backend/services/__init__.py b/legacy/backend_fastapi/services/__init__.py similarity index 100% rename from backend/services/__init__.py rename to legacy/backend_fastapi/services/__init__.py diff --git a/backend/services/report_service.py b/legacy/backend_fastapi/services/report_service.py similarity index 100% rename from backend/services/report_service.py rename to legacy/backend_fastapi/services/report_service.py diff --git a/backend/services/scan_service.py b/legacy/backend_fastapi/services/scan_service.py similarity index 100% rename from backend/services/scan_service.py rename to legacy/backend_fastapi/services/scan_service.py diff --git a/core/__init__.py b/legacy/core/__init__.py similarity index 100% rename from core/__init__.py rename to legacy/core/__init__.py diff --git a/core/browser_validator.py b/legacy/core/browser_validator.py similarity index 100% rename from core/browser_validator.py rename to legacy/core/browser_validator.py diff --git a/core/container_pool.py b/legacy/core/container_pool.py similarity index 100% rename from core/container_pool.py rename to legacy/core/container_pool.py diff --git a/core/context_builder.py b/legacy/core/context_builder.py similarity index 100% rename from core/context_builder.py rename to legacy/core/context_builder.py diff --git a/core/kali_sandbox.py b/legacy/core/kali_sandbox.py similarity index 100% rename from core/kali_sandbox.py rename to legacy/core/kali_sandbox.py diff --git a/core/knowledge_augmentor.py b/legacy/core/knowledge_augmentor.py similarity index 100% rename from core/knowledge_augmentor.py rename to legacy/core/knowledge_augmentor.py diff --git a/core/llm_manager.py b/legacy/core/llm_manager.py similarity index 100% rename from core/llm_manager.py rename to legacy/core/llm_manager.py diff --git a/core/mcp_client.py b/legacy/core/mcp_client.py similarity index 100% rename from core/mcp_client.py rename to legacy/core/mcp_client.py diff --git a/core/mcp_server.py b/legacy/core/mcp_server.py similarity index 100% rename from core/mcp_server.py rename to legacy/core/mcp_server.py diff --git a/core/model_router.py b/legacy/core/model_router.py similarity index 100% rename from core/model_router.py rename to legacy/core/model_router.py diff --git a/core/pentest_executor.py b/legacy/core/pentest_executor.py similarity index 100% rename from core/pentest_executor.py rename to legacy/core/pentest_executor.py diff --git a/core/report_generator.py b/legacy/core/report_generator.py similarity index 100% rename from core/report_generator.py rename to legacy/core/report_generator.py diff --git a/core/sandbox_manager.py b/legacy/core/sandbox_manager.py similarity index 100% rename from core/sandbox_manager.py rename to legacy/core/sandbox_manager.py diff --git a/core/scheduler.py b/legacy/core/scheduler.py similarity index 100% rename from core/scheduler.py rename to legacy/core/scheduler.py diff --git a/core/tool_installer.py b/legacy/core/tool_installer.py similarity index 100% rename from core/tool_installer.py rename to legacy/core/tool_installer.py diff --git a/core/tool_registry.py b/legacy/core/tool_registry.py similarity index 100% rename from core/tool_registry.py rename to legacy/core/tool_registry.py diff --git a/frontend/index.html b/legacy/frontend_react/index.html similarity index 100% rename from frontend/index.html rename to legacy/frontend_react/index.html diff --git a/frontend/package-lock.json b/legacy/frontend_react/package-lock.json similarity index 100% rename from frontend/package-lock.json rename to legacy/frontend_react/package-lock.json diff --git a/frontend/package.json b/legacy/frontend_react/package.json similarity index 100% rename from frontend/package.json rename to legacy/frontend_react/package.json diff --git a/frontend/postcss.config.js b/legacy/frontend_react/postcss.config.js similarity index 100% rename from frontend/postcss.config.js rename to legacy/frontend_react/postcss.config.js diff --git a/frontend/public/favicon.svg b/legacy/frontend_react/public/favicon.svg similarity index 100% rename from frontend/public/favicon.svg rename to legacy/frontend_react/public/favicon.svg diff --git a/frontend/src/App.tsx b/legacy/frontend_react/src/App.tsx similarity index 100% rename from frontend/src/App.tsx rename to legacy/frontend_react/src/App.tsx diff --git a/frontend/src/components/VulnAgentGrid.tsx b/legacy/frontend_react/src/components/VulnAgentGrid.tsx similarity index 100% rename from frontend/src/components/VulnAgentGrid.tsx rename to legacy/frontend_react/src/components/VulnAgentGrid.tsx diff --git a/frontend/src/components/common/Badge.tsx b/legacy/frontend_react/src/components/common/Badge.tsx similarity index 100% rename from frontend/src/components/common/Badge.tsx rename to legacy/frontend_react/src/components/common/Badge.tsx diff --git a/frontend/src/components/common/Button.tsx b/legacy/frontend_react/src/components/common/Button.tsx similarity index 100% rename from frontend/src/components/common/Button.tsx rename to legacy/frontend_react/src/components/common/Button.tsx diff --git a/frontend/src/components/common/Card.tsx b/legacy/frontend_react/src/components/common/Card.tsx similarity index 100% rename from frontend/src/components/common/Card.tsx rename to legacy/frontend_react/src/components/common/Card.tsx diff --git a/frontend/src/components/common/Input.tsx b/legacy/frontend_react/src/components/common/Input.tsx similarity index 100% rename from frontend/src/components/common/Input.tsx rename to legacy/frontend_react/src/components/common/Input.tsx diff --git a/frontend/src/components/common/Textarea.tsx b/legacy/frontend_react/src/components/common/Textarea.tsx similarity index 100% rename from frontend/src/components/common/Textarea.tsx rename to legacy/frontend_react/src/components/common/Textarea.tsx diff --git a/frontend/src/components/layout/Header.tsx b/legacy/frontend_react/src/components/layout/Header.tsx similarity index 100% rename from frontend/src/components/layout/Header.tsx rename to legacy/frontend_react/src/components/layout/Header.tsx diff --git a/frontend/src/components/layout/Layout.tsx b/legacy/frontend_react/src/components/layout/Layout.tsx similarity index 100% rename from frontend/src/components/layout/Layout.tsx rename to legacy/frontend_react/src/components/layout/Layout.tsx diff --git a/frontend/src/components/layout/Sidebar.tsx b/legacy/frontend_react/src/components/layout/Sidebar.tsx similarity index 100% rename from frontend/src/components/layout/Sidebar.tsx rename to legacy/frontend_react/src/components/layout/Sidebar.tsx diff --git a/frontend/src/main.tsx b/legacy/frontend_react/src/main.tsx similarity index 100% rename from frontend/src/main.tsx rename to legacy/frontend_react/src/main.tsx diff --git a/frontend/src/pages/AgentStatusPage.tsx b/legacy/frontend_react/src/pages/AgentStatusPage.tsx similarity index 100% rename from frontend/src/pages/AgentStatusPage.tsx rename to legacy/frontend_react/src/pages/AgentStatusPage.tsx diff --git a/frontend/src/pages/AutoPentestPage.tsx b/legacy/frontend_react/src/pages/AutoPentestPage.tsx similarity index 100% rename from frontend/src/pages/AutoPentestPage.tsx rename to legacy/frontend_react/src/pages/AutoPentestPage.tsx diff --git a/frontend/src/pages/FullIATestingPage.tsx b/legacy/frontend_react/src/pages/FullIATestingPage.tsx similarity index 100% rename from frontend/src/pages/FullIATestingPage.tsx rename to legacy/frontend_react/src/pages/FullIATestingPage.tsx diff --git a/frontend/src/pages/HomePage.tsx b/legacy/frontend_react/src/pages/HomePage.tsx similarity index 100% rename from frontend/src/pages/HomePage.tsx rename to legacy/frontend_react/src/pages/HomePage.tsx diff --git a/frontend/src/pages/KnowledgePage.tsx b/legacy/frontend_react/src/pages/KnowledgePage.tsx similarity index 100% rename from frontend/src/pages/KnowledgePage.tsx rename to legacy/frontend_react/src/pages/KnowledgePage.tsx diff --git a/frontend/src/pages/MCPManagementPage.tsx b/legacy/frontend_react/src/pages/MCPManagementPage.tsx similarity index 100% rename from frontend/src/pages/MCPManagementPage.tsx rename to legacy/frontend_react/src/pages/MCPManagementPage.tsx diff --git a/frontend/src/pages/NewScanPage.tsx b/legacy/frontend_react/src/pages/NewScanPage.tsx similarity index 100% rename from frontend/src/pages/NewScanPage.tsx rename to legacy/frontend_react/src/pages/NewScanPage.tsx diff --git a/frontend/src/pages/ProvidersPage.tsx b/legacy/frontend_react/src/pages/ProvidersPage.tsx similarity index 100% rename from frontend/src/pages/ProvidersPage.tsx rename to legacy/frontend_react/src/pages/ProvidersPage.tsx diff --git a/frontend/src/pages/RealtimeTaskPage.tsx b/legacy/frontend_react/src/pages/RealtimeTaskPage.tsx similarity index 100% rename from frontend/src/pages/RealtimeTaskPage.tsx rename to legacy/frontend_react/src/pages/RealtimeTaskPage.tsx diff --git a/frontend/src/pages/ReportViewPage.tsx b/legacy/frontend_react/src/pages/ReportViewPage.tsx similarity index 100% rename from frontend/src/pages/ReportViewPage.tsx rename to legacy/frontend_react/src/pages/ReportViewPage.tsx diff --git a/frontend/src/pages/ReportsPage.tsx b/legacy/frontend_react/src/pages/ReportsPage.tsx similarity index 100% rename from frontend/src/pages/ReportsPage.tsx rename to legacy/frontend_react/src/pages/ReportsPage.tsx diff --git a/frontend/src/pages/SandboxDashboardPage.tsx b/legacy/frontend_react/src/pages/SandboxDashboardPage.tsx similarity index 100% rename from frontend/src/pages/SandboxDashboardPage.tsx rename to legacy/frontend_react/src/pages/SandboxDashboardPage.tsx diff --git a/frontend/src/pages/ScanDetailsPage.tsx b/legacy/frontend_react/src/pages/ScanDetailsPage.tsx similarity index 100% rename from frontend/src/pages/ScanDetailsPage.tsx rename to legacy/frontend_react/src/pages/ScanDetailsPage.tsx diff --git a/frontend/src/pages/SchedulerPage.tsx b/legacy/frontend_react/src/pages/SchedulerPage.tsx similarity index 100% rename from frontend/src/pages/SchedulerPage.tsx rename to legacy/frontend_react/src/pages/SchedulerPage.tsx diff --git a/frontend/src/pages/SettingsPage.tsx b/legacy/frontend_react/src/pages/SettingsPage.tsx similarity index 100% rename from frontend/src/pages/SettingsPage.tsx rename to legacy/frontend_react/src/pages/SettingsPage.tsx diff --git a/frontend/src/pages/TaskLibraryPage.tsx b/legacy/frontend_react/src/pages/TaskLibraryPage.tsx similarity index 100% rename from frontend/src/pages/TaskLibraryPage.tsx rename to legacy/frontend_react/src/pages/TaskLibraryPage.tsx diff --git a/frontend/src/pages/TerminalAgentPage.tsx b/legacy/frontend_react/src/pages/TerminalAgentPage.tsx similarity index 100% rename from frontend/src/pages/TerminalAgentPage.tsx rename to legacy/frontend_react/src/pages/TerminalAgentPage.tsx diff --git a/frontend/src/pages/VulnLabPage.tsx b/legacy/frontend_react/src/pages/VulnLabPage.tsx similarity index 100% rename from frontend/src/pages/VulnLabPage.tsx rename to legacy/frontend_react/src/pages/VulnLabPage.tsx diff --git a/frontend/src/services/api.ts b/legacy/frontend_react/src/services/api.ts similarity index 100% rename from frontend/src/services/api.ts rename to legacy/frontend_react/src/services/api.ts diff --git a/frontend/src/services/websocket.ts b/legacy/frontend_react/src/services/websocket.ts similarity index 100% rename from frontend/src/services/websocket.ts rename to legacy/frontend_react/src/services/websocket.ts diff --git a/frontend/src/store/index.ts b/legacy/frontend_react/src/store/index.ts similarity index 100% rename from frontend/src/store/index.ts rename to legacy/frontend_react/src/store/index.ts diff --git a/frontend/src/styles/globals.css b/legacy/frontend_react/src/styles/globals.css similarity index 100% rename from frontend/src/styles/globals.css rename to legacy/frontend_react/src/styles/globals.css diff --git a/frontend/src/types/index.ts b/legacy/frontend_react/src/types/index.ts similarity index 100% rename from frontend/src/types/index.ts rename to legacy/frontend_react/src/types/index.ts diff --git a/frontend/tailwind.config.js b/legacy/frontend_react/tailwind.config.js similarity index 100% rename from frontend/tailwind.config.js rename to legacy/frontend_react/tailwind.config.js diff --git a/frontend/tsconfig.json b/legacy/frontend_react/tsconfig.json similarity index 100% rename from frontend/tsconfig.json rename to legacy/frontend_react/tsconfig.json diff --git a/frontend/tsconfig.node.json b/legacy/frontend_react/tsconfig.node.json similarity index 100% rename from frontend/tsconfig.node.json rename to legacy/frontend_react/tsconfig.node.json diff --git a/frontend/vite.config.ts b/legacy/frontend_react/vite.config.ts similarity index 100% rename from frontend/vite.config.ts rename to legacy/frontend_react/vite.config.ts diff --git a/test_agent_run.py b/legacy/test_agent_run.py similarity index 100% rename from test_agent_run.py rename to legacy/test_agent_run.py diff --git a/neurosploit_agent/backends.py b/neurosploit_agent/backends.py index 919223d..dc8e6d2 100644 --- a/neurosploit_agent/backends.py +++ b/neurosploit_agent/backends.py @@ -122,18 +122,30 @@ class RunResult: def run(backend: Backend, prompt: str, workdir: str, model: str = "", autonomous: bool = True, mcp_config: Optional[str] = None, env: Optional[Dict[str, str]] = None, timeout: int = 7200, - dry_run: bool = False) -> RunResult: - """Execute a backend against the composed prompt and stream logs to disk.""" + dry_run: bool = False, on_start=None) -> RunResult: + """Execute a backend against the composed prompt and stream logs to disk. + + on_start(argv): optional callback invoked with the exact command line, so + callers/UI can show precisely what is being executed behind the scenes. + """ os.makedirs(workdir, exist_ok=True) prompt_file = os.path.join(workdir, "master_prompt.md") open(prompt_file, "w", encoding="utf-8").write(prompt) log_path = os.path.join(workdir, "backend.log") argv = backend.build_argv(prompt_file, workdir, model, autonomous, mcp_config) + if on_start: + on_start(argv) full_env = os.environ.copy() if env: full_env.update(env) + # Claude Code refuses --dangerously-skip-permissions when running as root + # unless IS_SANDBOX=1 is set. The engine already isolates each run in its own + # workdir, so opt into the sandbox flag rather than failing rc=1 under root. + if autonomous and backend.key == "claude" and hasattr(os, "geteuid") and os.geteuid() == 0: + full_env.setdefault("IS_SANDBOX", "1") + if dry_run: open(log_path, "w").write("DRY RUN\n" + " ".join(argv) + "\n") return RunResult(backend.key, 0, log_path, workdir) diff --git a/neurosploit_agent/models.py b/neurosploit_agent/models.py index 672feb3..978b4cd 100644 --- a/neurosploit_agent/models.py +++ b/neurosploit_agent/models.py @@ -30,12 +30,13 @@ class Provider: base_url_env: Optional[str] = None # env var the backend reads for base URL models: List[Model] = field(default_factory=list) subscription: bool = False # uses a CLI subscription rather than an API key + kind: str = "api" # "cli" (native agentic CLI) | "api" (OpenAI-compatible) PROVIDERS: Dict[str, Provider] = { # --- Anthropic (latest Claude family; default) ------------------------- "anthropic": Provider( - key="anthropic", label="Anthropic Claude", + key="anthropic", label="Anthropic Claude", kind="cli", env_keys=["ANTHROPIC_API_KEY"], models=[ Model("claude-opus-4-8", "Claude Opus 4.8", 1_000_000, "Most capable; deep multi-step pentest reasoning"), @@ -45,16 +46,17 @@ PROVIDERS: Dict[str, Provider] = { ), # --- OpenAI ------------------------------------------------------------ "openai": Provider( - key="openai", label="OpenAI", + key="openai", label="OpenAI", kind="cli", env_keys=["OPENAI_API_KEY"], models=[ Model("gpt-5.1", "GPT-5.1", 400_000, "Strong general reasoning"), + Model("gpt-5.1-codex", "GPT-5.1 Codex", 400_000, "Codex CLI default"), Model("o4", "o4", 200_000, "Deliberate reasoning for validation"), ], ), # --- xAI Grok ---------------------------------------------------------- "xai": Provider( - key="xai", label="xAI Grok", + key="xai", label="xAI Grok", kind="cli", env_keys=["XAI_API_KEY", "GROK_API_KEY"], base_url="https://api.x.ai/v1", base_url_env="OPENAI_BASE_URL", models=[ @@ -72,6 +74,56 @@ PROVIDERS: Dict[str, Provider] = { Model("nvidia/llama-3.3-nemotron-super-49b-v1", "Nemotron Super 49B", 128_000, "NIM hosted reasoning"), Model("deepseek-ai/deepseek-r1", "DeepSeek-R1 (NIM)", 128_000, "Strong reasoning via NIM"), Model("qwen/qwen2.5-coder-32b-instruct", "Qwen2.5 Coder 32B (NIM)", 128_000, "Code/exploit oriented"), + Model("qwen/qwq-32b", "QwQ 32B (NIM)", 128_000, "Reasoning"), + Model("meta/llama-3.3-70b-instruct", "Llama 3.3 70B (NIM)", 128_000), + Model("mistralai/mistral-large-2-instruct", "Mistral Large 2 (NIM)", 128_000), + ], + ), + # --- DeepSeek (direct API) -------------------------------------------- + "deepseek": Provider( + key="deepseek", label="DeepSeek", env_keys=["DEEPSEEK_API_KEY"], + base_url="https://api.deepseek.com/v1", base_url_env="OPENAI_BASE_URL", + models=[ + Model("deepseek-reasoner", "DeepSeek-R1 (reasoner)", 64_000, "Deep reasoning"), + Model("deepseek-chat", "DeepSeek-V3 (chat)", 64_000), + ], + ), + # --- Mistral (direct API) --------------------------------------------- + "mistral": Provider( + key="mistral", label="Mistral", env_keys=["MISTRAL_API_KEY"], + base_url="https://api.mistral.ai/v1", base_url_env="OPENAI_BASE_URL", + models=[ + Model("mistral-large-latest", "Mistral Large", 128_000), + Model("codestral-latest", "Codestral", 256_000, "Code/exploit oriented"), + ], + ), + # --- Alibaba Qwen (DashScope, OpenAI-compatible) ---------------------- + "qwen": Provider( + key="qwen", label="Qwen (DashScope)", env_keys=["DASHSCOPE_API_KEY", "QWEN_API_KEY"], + base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1", base_url_env="OPENAI_BASE_URL", + models=[ + Model("qwen-max", "Qwen Max", 32_000), + Model("qwen2.5-coder-32b-instruct", "Qwen2.5 Coder 32B", 128_000, "Code/exploit oriented"), + Model("qwq-plus", "QwQ Plus", 128_000, "Reasoning"), + ], + ), + # --- Groq (fast OpenAI-compatible) ------------------------------------ + "groq": Provider( + key="groq", label="Groq", env_keys=["GROQ_API_KEY"], + base_url="https://api.groq.com/openai/v1", base_url_env="OPENAI_BASE_URL", + models=[ + Model("llama-3.3-70b-versatile", "Llama 3.3 70B (Groq)", 128_000, "Very fast"), + Model("qwen-2.5-coder-32b", "Qwen2.5 Coder 32B (Groq)", 128_000), + ], + ), + # --- Together AI ------------------------------------------------------ + "together": Provider( + key="together", label="Together AI", env_keys=["TOGETHER_API_KEY"], + base_url="https://api.together.xyz/v1", base_url_env="OPENAI_BASE_URL", + models=[ + Model("Qwen/Qwen2.5-Coder-32B-Instruct", "Qwen2.5 Coder 32B", 128_000), + Model("deepseek-ai/DeepSeek-R1", "DeepSeek-R1", 128_000), + Model("meta-llama/Llama-3.3-70B-Instruct-Turbo", "Llama 3.3 70B Turbo", 128_000), ], ), # --- Google Gemini ----------------------------------------------------- @@ -88,7 +140,14 @@ PROVIDERS: Dict[str, Provider] = { key="openrouter", label="OpenRouter", env_keys=["OPENROUTER_API_KEY"], base_url="https://openrouter.ai/api/v1", base_url_env="OPENAI_BASE_URL", - models=[Model("anthropic/claude-opus-4-8", "Opus 4.8 (OpenRouter)", 1_000_000)], + models=[ + Model("anthropic/claude-opus-4-8", "Opus 4.8 (OpenRouter)", 1_000_000), + Model("qwen/qwen-2.5-coder-32b-instruct", "Qwen2.5 Coder 32B", 128_000), + Model("deepseek/deepseek-r1", "DeepSeek-R1", 128_000), + Model("meta-llama/llama-3.3-70b-instruct", "Llama 3.3 70B", 128_000), + Model("mistralai/mistral-large", "Mistral Large", 128_000), + Model("x-ai/grok-4", "Grok 4", 256_000), + ], ), # --- Local Ollama ------------------------------------------------------ "ollama": Provider( @@ -97,6 +156,8 @@ PROVIDERS: Dict[str, Provider] = { base_url="http://localhost:11434/v1", base_url_env="OPENAI_BASE_URL", models=[ Model("qwen2.5-coder:32b", "Qwen2.5 Coder 32B (local)", 32_000), + Model("qwq:32b", "QwQ 32B (local)", 32_000, "Reasoning"), + Model("deepseek-r1:32b", "DeepSeek-R1 32B (local)", 64_000), Model("llama3.3:70b", "Llama 3.3 70B (local)", 128_000), ], ), diff --git a/neurosploit_agent/orchestrator.py b/neurosploit_agent/orchestrator.py index 3f3de29..806a976 100644 --- a/neurosploit_agent/orchestrator.py +++ b/neurosploit_agent/orchestrator.py @@ -12,7 +12,7 @@ import json import os from typing import Dict, List, Optional -from . import backends, mcp, models +from . import backends, mcp, models, report from .agent_loader import AgentLibrary from .config import RunConfig, PATHS, ensure_dirs from .rl import RLEngine, outcomes_from_findings @@ -70,11 +70,19 @@ and follow its methodology and (strict) anti-false-positive System Prompt. 6. `meta/reporter.md` → write `results/findings.json` AND `reports/report.md`. 7. `meta/rl_feedback.md` → write/merge `data/rl_state.json`. +## Evidence: screenshots (MANDATORY for confirmed findings) +For every confirmed finding, use Playwright MCP to capture a screenshot proving +the issue (e.g. the executed XSS alert/DOM, the exposed data, the error oracle). +Save it under `{cfg.resolved_workdir()}/shots/.png` and record that +relative path in the finding's `screenshot` field. + ## Output contract (MANDATORY) Write `results/findings.json` as a JSON array of objects: -{{"id","agent","title","severity","cvss","cwe","endpoint","payload","evidence","impact","remediation","confidence","validated"}} +{{"id","agent","title","severity","cvss","cwe","endpoint","payload","evidence","impact","remediation","confidence","validated","screenshot"}} Only include findings with `validated: true`. If you find nothing, write `[]`. -Also write `results/agents_ran.json` as a JSON array of the agent names you executed. +Also write `results/agents_ran.json` as a JSON array of the agent names you executed, +and `results/activity.json` as an array of `{{"agent","status","note"}}` task records +so the dashboard can show what was executed. Stay strictly in scope. Never run destructive/DoS payloads unless ROE permits. Report ONLY proven, reproducible findings. @@ -83,23 +91,19 @@ Report ONLY proven, reproducible findings. def collect_results(workdir: str) -> Dict: - findings, ran = [], [] - fpath = os.path.join(workdir, "findings.json") - rpath = os.path.join(workdir, "agents_ran.json") + collected = {"findings": [], "agents_ran": [], "activity": []} + files = {"findings.json": "findings", "agents_ran.json": "agents_ran", + "activity.json": "activity"} # The backend may write under results// or results/ — check both. for base in (workdir, PATHS["results"]): - for name, sink in (("findings.json", "findings"), ("agents_ran.json", "ran")): + for name, sink in files.items(): p = os.path.join(base, name) - if os.path.exists(p): + if not collected[sink] and os.path.exists(p): try: - data = json.load(open(p, encoding="utf-8")) - if sink == "findings" and not findings: - findings = data - elif sink == "ran" and not ran: - ran = data + collected[sink] = json.load(open(p, encoding="utf-8")) except Exception: pass - return {"findings": findings, "agents_ran": ran} + return collected def run_engagement(cfg: RunConfig, recon: Optional[dict] = None, @@ -131,14 +135,24 @@ def run_engagement(cfg: RunConfig, recon: Optional[dict] = None, progress(f"Launching {backend.label} ({cfg.model}) — autonomous={cfg.autonomous}") res = backends.run(backend, prompt, workdir, model=cfg.model, autonomous=cfg.autonomous, mcp_config=mcp_cfg, env=env, - timeout=cfg.timeout, dry_run=cfg.dry_run) + timeout=cfg.timeout, dry_run=cfg.dry_run, + on_start=lambda argv: progress("exec: " + " ".join(argv))) progress(f"Backend exited rc={res.returncode}; log: {res.log_path}") out = collect_results(workdir) findings = out["findings"] or [] ran = out["agents_ran"] or [] + activity = out["activity"] or [] progress(f"Collected {len(findings)} validated finding(s) from {len(ran)} agent(s)") + reports = {} + if not cfg.dry_run: + try: + reports = report.generate(cfg.target, findings, PATHS["reports"]) + progress("Report generated: " + ", ".join(k for k in reports if not k.endswith("_error"))) + except Exception as e: + progress(f"Report generation skipped: {e}") + if cfg.use_rl and not cfg.dry_run: tech = ((recon or {}).get("tech", {}) or {}).get("framework", "") or None outcomes = outcomes_from_findings(findings, ran, tech=tech) @@ -147,4 +161,5 @@ def run_engagement(cfg: RunConfig, recon: Optional[dict] = None, progress("RL state updated → data/rl_state.json") return {"workdir": workdir, "returncode": res.returncode, - "findings": findings, "agents_ran": ran, "log": res.log_path} + "findings": findings, "agents_ran": ran, "activity": activity, + "reports": reports, "log": res.log_path} diff --git a/neurosploit_agent/report.py b/neurosploit_agent/report.py new file mode 100644 index 0000000..a6bb5b9 --- /dev/null +++ b/neurosploit_agent/report.py @@ -0,0 +1,152 @@ +""" +Report generation for NeuroSploit v3.3.0. + +Produces a polished **HTML** report from a run's validated findings, plus a +**PDF** via the Typst engine when the `typst` binary is available (it is the +intended report engine; HTML is always emitted as a fallback/companion). + + from neurosploit_agent.report import generate + paths = generate(target, findings, out_dir) # -> {"html":..., "pdf":..., "typ":...} +""" + +import datetime +import html +import os +import shutil +import subprocess +from typing import Dict, List, Optional + +SEV_ORDER = {"Critical": 0, "High": 1, "Medium": 2, "Low": 3, "Info": 4} +SEV_COLOR = {"Critical": "#c0392b", "High": "#e67e22", "Medium": "#f1c40f", + "Low": "#3498db", "Info": "#7f8c8d"} + + +def _sorted(findings: List[Dict]) -> List[Dict]: + return sorted(findings, key=lambda f: SEV_ORDER.get(f.get("severity", "Info"), 9)) + + +def _counts(findings: List[Dict]) -> Dict[str, int]: + c = {} + for f in findings: + c[f.get("severity", "Info")] = c.get(f.get("severity", "Info"), 0) + 1 + return c + + +def typst_available() -> bool: + return shutil.which("typst") is not None + + +# --------------------------------------------------------------------------- HTML +def render_html(target: str, findings: List[Dict], when: str) -> str: + counts = _counts(findings) + chips = "".join( + f'{s}: {n}' + for s, n in sorted(counts.items(), key=lambda kv: SEV_ORDER.get(kv[0], 9)) + ) or 'No validated findings' + rows = [] + for i, f in enumerate(_sorted(findings), 1): + sev = f.get("severity", "Info") + rows.append(f""" +
+

{html.escape(sev)} + {i}. {html.escape(str(f.get('title','Untitled')))}

+ + + + + + +
Agent{html.escape(str(f.get('agent','')))}CWE{html.escape(str(f.get('cwe','')))}
CVSS{html.escape(str(f.get('cvss','')))}Confidence{html.escape(str(f.get('confidence','')))}
Endpoint{html.escape(str(f.get('endpoint','')))}
+

Payload

{html.escape(str(f.get('payload','')))}
+

Evidence

{html.escape(str(f.get('evidence','')))}
+

Impact

{html.escape(str(f.get('impact','')))}

+

Remediation

{html.escape(str(f.get('remediation','')))}

+
""") + body = "\n".join(rows) or "

No validated findings were produced for this engagement.

" + return f""" +NeuroSploit Report — {html.escape(target)} + +

NeuroSploit Penetration Test Report

+
Target: {html.escape(target)} · Generated {html.escape(when)} · v3.3.0 Autonomous MD-Agent Engine
+
{chips}
+

Findings ({len(findings)})

+{body} +
Authorized testing only. All findings were independently validated and false-positive-filtered before inclusion.
+""" + + +# --------------------------------------------------------------------------- Typst +def render_typst(target: str, findings: List[Dict], when: str) -> str: + def s(v): + """Safely embed arbitrary text as a Typst string literal (// is inert).""" + return '"' + str(v).replace("\\", "\\\\").replace('"', '\\"').replace("\n", " ") + '"' + + counts = _counts(findings) + summary = ", ".join(f"{k}: {n}" for k, n in sorted(counts.items(), key=lambda kv: SEV_ORDER.get(kv[0], 9))) or "No validated findings" + parts = [f'''#set page(margin: 2cm, numbering: "1") +#set text(size: 10pt) +#let sevcolor = (Critical: rgb("#c0392b"), High: rgb("#e67e22"), Medium: rgb("#f1c40f"), Low: rgb("#3498db"), Info: rgb("#7f8c8d")) +#let sev(label) = box(fill: sevcolor.at(label, default: rgb("#7f8c8d")), inset: 3pt, radius: 3pt, text(fill: white, weight: "bold", label)) +#align(center)[#text(20pt, weight: "bold")[#text(fill: rgb("#8b5cf6"))[NeuroSploit] Penetration Test Report]] +#align(center)[Target: #strong(target) #h(6pt) Generated {s(when)} #h(6pt) v3.3.0] +#line(length: 100%, stroke: 0.5pt + gray) +#strong[Summary:] {s(summary)} +#v(6pt) +== Findings ({len(findings)}) +'''.replace("#strong(target)", f"#strong({s(target)})")] + for i, f in enumerate(_sorted(findings), 1): + parts.append(f''' +#block(breakable: false, stroke: 0.5pt + rgb("#dddddd"), radius: 6pt, inset: 10pt, width: 100%)[ + #sev({s(f.get('severity','Info'))}) #h(4pt) #strong[{i}. ] #strong({s(f.get('title','Untitled'))}) + #v(4pt) + Agent: {s(f.get('agent',''))} #h(6pt) CWE: {s(f.get('cwe',''))} #h(6pt) CVSS: {s(f.get('cvss',''))} + #v(2pt) Endpoint: #raw({s(f.get('endpoint',''))}) + #v(4pt) #strong[Payload] #linebreak() #raw({s(f.get('payload',''))}) + #v(2pt) #strong[Evidence] #linebreak() #raw({s(f.get('evidence',''))}) + #v(2pt) #strong[Impact:] {s(f.get('impact',''))} + #v(2pt) #strong[Remediation:] {s(f.get('remediation',''))} +]''') + if not findings: + parts.append("\n#emph[No validated findings were produced for this engagement.]\n") + return "\n".join(parts) + + +# --------------------------------------------------------------------------- API +def generate(target: str, findings: List[Dict], out_dir: str, + when: Optional[str] = None) -> Dict[str, str]: + os.makedirs(out_dir, exist_ok=True) + when = when or datetime.datetime.now().strftime("%Y-%m-%d %H:%M") + out: Dict[str, str] = {} + + html_path = os.path.join(out_dir, "report.html") + open(html_path, "w").write(render_html(target, findings, when)) + out["html"] = html_path + + typ_path = os.path.join(out_dir, "report.typ") + open(typ_path, "w").write(render_typst(target, findings, when)) + out["typ"] = typ_path + + if typst_available(): + pdf_path = os.path.join(out_dir, "report.pdf") + try: + r = subprocess.run(["typst", "compile", typ_path, pdf_path], + capture_output=True, text=True, timeout=120) + if r.returncode == 0 and os.path.exists(pdf_path): + out["pdf"] = pdf_path + else: + out["pdf_error"] = (r.stderr or "typst failed").strip()[:400] + except Exception as e: + out["pdf_error"] = str(e) + else: + out["pdf_error"] = "typst binary not found" + return out diff --git a/webgui/index.html b/webgui/index.html index fa3face..c3830f3 100644 --- a/webgui/index.html +++ b/webgui/index.html @@ -6,171 +6,351 @@ NeuroSploit v3.3.0 -
-
- -

NeuroSploit v3.3.0

-
-
Autonomous MD-Agent pentest — enter a URL, pick a backend, run.
+ -
-
- - -
- -
-
- - +
+ +
+

Run engagement

Autonomous, validated, false-positive-filtered.
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+
+ + +
-
- - +
+ + +
+

Agent library

+
+
+
-
+
+

Add a new .md agent

+
Dropped into agents_md/vulns/ and orchestrated by the main agent on the next run.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
- - -
+ +
+

Insights

Agent outputs & reinforcement-learning weights.
+
+
+

Findings by severity (last run)

+
Run an engagement to populate.
+
+
+

RL agent weights

+
Higher = historically more productive. Updated after every run.
+
No RL history yet.
+
+
-
- - -
+ +
+

Reports

PDF + HTML, generated via Typst.
+
+
+
No reports yet — run an engagement.
+
+
+
-
- - -
- -
- agents - backends - Playwright proof-of-exec -
- -
-
-
- -
Authorized testing only · findings are validated & false-positive-filtered before reporting
-
+ +
+

Settings · API

Execution mode, provider keys, orchestrator.
+
+
+
+
+
+
+
+
+

Provider API keys

+
Stored in memory for this session (only key presence is persisted to disk). Enables “via API” model use.
+
+
+
+
+
+ diff --git a/webgui/server.py b/webgui/server.py index 743af9a..c20139a 100644 --- a/webgui/server.py +++ b/webgui/server.py @@ -1,10 +1,13 @@ #!/usr/bin/env python3 """ -NeuroSploit v3.3.0 — minimalist web GUI server. +NeuroSploit v3.3.0 — minimalist web GUI server (stdlib only). -A tiny, dependency-free (Python stdlib only) web front-end for the autonomous -engine. It exposes just the essential options — target URL, backend, model, -collaborator, and the RL / Playwright-MCP toggles — and launches an engagement. +A tiny, dependency-free web front-end for the autonomous engine. Tabs: + * Run — URL, backend/model, collaborator, verbosity, RL + MCP toggles + * Agents — browse the 213-agent library; add new .md agents from the UI + * Insights — interactive chart of agent outputs (findings + RL weights) + * Settings — API keys per provider, execution mode (CLI backend vs API), + main orchestrator agent python3 webgui/server.py # serves http://127.0.0.1:8787 @@ -13,6 +16,7 @@ No npm, no build step, no FastAPI. It talks to neurosploit_agent directly. import json import os +import re import sys import threading from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer @@ -21,32 +25,119 @@ ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, ROOT) from neurosploit_agent import backends, models # noqa: E402 -from neurosploit_agent.agent_loader import AgentLibrary # noqa: E402 -from neurosploit_agent.config import RunConfig # noqa: E402 +from neurosploit_agent.agent_loader import AgentLibrary, AGENTS_DIR # noqa: E402 +from neurosploit_agent.config import RunConfig, PATHS # noqa: E402 from neurosploit_agent.orchestrator import run_engagement # noqa: E402 +from neurosploit_agent.rl import RLEngine # noqa: E402 HERE = os.path.dirname(os.path.abspath(__file__)) -_RUNS = {} # run_id -> {log:[], done:bool, result:dict} +CONFIG_PATH = os.path.join(PATHS["data"], "gui_config.json") +_RUNS = {} _LOCK = threading.Lock() _PROV_FOR_BACKEND = {"claude": "anthropic", "codex": "openai", "grok": "xai"} +def _load_config(): + if os.path.exists(CONFIG_PATH): + try: + return json.load(open(CONFIG_PATH)) + except Exception: + pass + return {"mode": "cli", "orchestrator": "orchestrator", "verbosity": "normal", "api_keys": {}} + + +def _save_config(cfg): + os.makedirs(PATHS["data"], exist_ok=True) + safe = dict(cfg) + # Persist key *presence*, not raw secrets, to disk; live keys go to env only. + safe["api_keys"] = {k: ("set" if v else "") for k, v in cfg.get("api_keys", {}).items()} + json.dump(safe, open(CONFIG_PATH, "w"), indent=2) + + def _info(): lib = AgentLibrary() det = backends.detect() - provs = {} - for p in models.PROVIDERS.values(): - provs[p.key] = {"label": p.label, - "models": [{"id": m.id, "label": m.label} for m in p.models]} + provs = {p.key: {"label": p.label, "env_keys": p.env_keys, "subscription": p.subscription, + "models": [{"id": m.id, "label": m.label} for m in p.models]} + for p in models.PROVIDERS.values()} + cfg = _load_config() return { "version": "3.3.0", "agents": lib.counts(), "backends": [{"key": b.key, "label": b.label, "version": b.version()} for b in det], "providers": provs, "backend_provider": _PROV_FOR_BACKEND, + "orchestrators": sorted(lib.meta.keys()), + "config": cfg, } +def _agents_list(): + lib = AgentLibrary() + out = [] + for kind, store in (("vuln", lib.vulns), ("meta", lib.meta)): + for name, a in store.items(): + out.append({"name": name, "title": a.title, "cwe": a.cwe, + "severity": a.severity, "kind": kind}) + out.sort(key=lambda x: (x["kind"] != "vuln", x["name"])) + return out + + +def _add_agent(p): + name = re.sub(r"[^a-z0-9_]+", "_", (p.get("name") or "").strip().lower()).strip("_") + if not name: + raise ValueError("name required") + path = os.path.join(AGENTS_DIR, "vulns", name + ".md") + if os.path.exists(path): + raise ValueError("agent already exists") + title = p.get("title") or name.replace("_", " ").title() + steps = p.get("methodology", "").strip() or "- Describe the test methodology here" + md = f"""# {title} Agent + +## User Prompt +You are testing **{{target}}** for {p.get('for', title)}. + +**Recon Context:** +{{recon_json}} + +**METHODOLOGY:** + +### 1. Methodology +{steps} + +### 2. Report Format +For each CONFIRMED finding: +``` +FINDING: +- Title: {title} at [endpoint] +- Severity: {p.get('severity', 'Medium')} +- CWE: {p.get('cwe', 'CWE-0')} +- Endpoint: [full URL] +- Vector: [parameter/header/flow] +- Payload: [exact payload] +- Evidence: [proof of exploitation] +- Impact: {p.get('impact', 'Describe impact')} +- Remediation: {p.get('fix', 'Describe remediation')} +``` + +## System Prompt +{p.get('system', 'You are a specialist. Report only reproducible, proven findings with hard evidence. Never report unverified or theoretical issues.')} +""" + os.makedirs(os.path.dirname(path), exist_ok=True) + open(path, "w").write(md) + return {"name": name, "path": os.path.relpath(path, ROOT)} + + +def _rl_state(): + rl = RLEngine(PATHS["rl_state"]) + agents = rl.state.get("agents", {}) + rows = [{"name": n, "weight": r.get("weight", 0.5), "runs": r.get("runs", 0), + "hits": r.get("validated_hits", 0), "fp": r.get("false_positives", 0)} + for n, r in agents.items()] + rows.sort(key=lambda x: x["weight"], reverse=True) + return {"agents": rows, "updated_for": rl.state.get("updated_for", "")} + + def _start_run(params): run_id = "run-%d" % (len(_RUNS) + 1) with _LOCK: @@ -58,26 +149,54 @@ def _start_run(params): def worker(): try: + cfg_g = _load_config() + # Apply API keys from settings to env (API execution mode). + for prov, key in (params.get("api_keys") or cfg_g.get("api_keys") or {}).items(): + p = models.PROVIDERS.get(prov) + if p and key and p.env_keys: + os.environ[p.env_keys[0]] = key backend = params.get("backend") or (backends.detect()[0].key if backends.detect() else "claude") provider = params.get("provider") or _PROV_FOR_BACKEND.get(backend, "anthropic") mlist = models.list_models(provider) model = params.get("model") or (mlist[0].id if mlist else "") - url = params["url"] - if not url.startswith(("http://", "https://")): - url = "https://" + url - cfg = RunConfig( - target=url, scope=params.get("scope") or url, backend=backend, - provider=provider, model=model, collaborator=params.get("collaborator", ""), - use_rl=bool(params.get("rl", True)), use_mcp=bool(params.get("mcp", True)), - dry_run=bool(params.get("dry_run", False)), - ) - res = run_engagement(cfg, progress=progress) + verbosity = params.get("verbosity", cfg_g.get("verbosity", "normal")) + mode = params.get("mode", cfg_g.get("mode", "cli")) + + # Multi-target: accept "targets" list or single "url". + raw = params.get("targets") or [params.get("url")] + targets = [] + for u in raw: + if not u: + continue + targets.append(u if u.startswith(("http://", "https://")) else "https://" + u) + if verbosity != "quiet": + progress(f"verbosity={verbosity} mode={mode} provider={provider} model={model} targets={len(targets)}") + + all_findings, all_ran, all_activity, reports = [], [], [], {} + for idx, url in enumerate(targets, 1): + progress(f"=== target {idx}/{len(targets)}: {url} ===") + cfg = RunConfig( + target=url, scope=params.get("scope") or url, backend=backend, + provider=provider, model=model, collaborator=params.get("collaborator", ""), + use_rl=bool(params.get("rl", True)), use_mcp=bool(params.get("mcp", True)), + dry_run=bool(params.get("dry_run", False)), + ) + res = run_engagement(cfg, progress=progress) + for f in res.get("findings", []): + f.setdefault("target", url) + all_findings += res.get("findings", []) + all_ran += res.get("agents_ran", []) + all_activity += res.get("activity", []) + if res.get("reports"): + reports = res["reports"] with _LOCK: _RUNS[run_id]["result"] = { - "returncode": res["returncode"], "workdir": res["workdir"], - "findings": res["findings"], "agents_ran": res["agents_ran"], + "returncode": 0, "targets": targets, + "findings": all_findings, "agents_ran": all_ran, + "activity": all_activity, "reports": { + k: os.path.relpath(v, ROOT) for k, v in reports.items() if not k.endswith("_error")}, } - except Exception as e: # surface errors to the UI + except Exception as e: progress(f"ERROR: {e}") with _LOCK: _RUNS[run_id]["result"] = {"error": str(e)} @@ -98,34 +217,87 @@ class Handler(BaseHTTPRequestHandler): self.end_headers() self.wfile.write(data) + def _json_body(self): + n = int(self.headers.get("Content-Length", 0)) + try: + return json.loads(self.rfile.read(n) or b"{}") + except Exception: + return None + def log_message(self, *a): pass + def _serve_file(self): + # Serve generated reports and finding screenshots (read-only, path-scoped). + if self.path.startswith("/reports/"): + base, rel = PATHS["reports"], self.path[len("/reports/"):] + else: + base, rel = PATHS["results"], self.path[len("/shots/"):] + target = os.path.normpath(os.path.join(base, rel)) + if not target.startswith(os.path.normpath(base)) or not os.path.isfile(target): + return self._send(404, json.dumps({"error": "not found"})) + ext = os.path.splitext(target)[1].lower() + ctype = {".pdf": "application/pdf", ".html": "text/html; charset=utf-8", + ".png": "image/png", ".typ": "text/plain; charset=utf-8"}.get(ext, "application/octet-stream") + self._send(200, open(target, "rb").read(), ctype) + def do_GET(self): if self.path in ("/", "/index.html"): self._send(200, open(os.path.join(HERE, "index.html"), "rb").read(), "text/html; charset=utf-8") elif self.path == "/api/info": self._send(200, json.dumps(_info())) + elif self.path == "/api/agents": + self._send(200, json.dumps({"agents": _agents_list()})) + elif self.path == "/api/rl": + self._send(200, json.dumps(_rl_state())) + elif self.path == "/api/config": + self._send(200, json.dumps(_load_config())) + elif self.path == "/api/reports": + rdir = PATHS["reports"] + files = [] + if os.path.isdir(rdir): + for fn in sorted(os.listdir(rdir)): + fp = os.path.join(rdir, fn) + if os.path.isfile(fp) and fn.lower().endswith((".pdf", ".html", ".typ")): + files.append({"name": fn, "size": os.path.getsize(fp), + "url": "/reports/" + fn}) + self._send(200, json.dumps({"reports": files})) + elif self.path.startswith("/reports/") or self.path.startswith("/shots/"): + self._serve_file() elif self.path.startswith("/api/status/"): rid = self.path.rsplit("/", 1)[-1] with _LOCK: st = _RUNS.get(rid) - self._send(200 if st else 404, json.dumps(st or {"error": "unknown run"})) + self._send(200 if st else 404, json.dumps(st or {"error": "unknown run"})) else: self._send(404, json.dumps({"error": "not found"})) def do_POST(self): - if self.path != "/api/run": - return self._send(404, json.dumps({"error": "not found"})) - n = int(self.headers.get("Content-Length", 0)) - try: - params = json.loads(self.rfile.read(n) or b"{}") - except Exception: + body = self._json_body() + if body is None: return self._send(400, json.dumps({"error": "bad json"})) - if not params.get("url"): - return self._send(400, json.dumps({"error": "url required"})) - rid = _start_run(params) - self._send(200, json.dumps({"run_id": rid})) + if self.path == "/api/run": + if not body.get("url") and not body.get("targets"): + return self._send(400, json.dumps({"error": "url or targets required"})) + return self._send(200, json.dumps({"run_id": _start_run(body)})) + if self.path == "/api/agents": + try: + return self._send(200, json.dumps({"ok": True, "agent": _add_agent(body)})) + except Exception as e: + return self._send(400, json.dumps({"error": str(e)})) + if self.path == "/api/config": + cfg = _load_config() + cfg.update({k: v for k, v in body.items() if k in ("mode", "orchestrator", "verbosity")}) + keys = cfg.setdefault("api_keys", {}) + for prov, key in (body.get("api_keys") or {}).items(): + if key: + keys[prov] = key + p = models.PROVIDERS.get(prov) + if p and p.env_keys: + os.environ[p.env_keys[0]] = key # live, in-memory + _save_config(cfg) + return self._send(200, json.dumps({"ok": True})) + self._send(404, json.dumps({"error": "not found"})) def main():