mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-07-09 20:58:38 +02:00
v3.3.0 GUI dashboard + reports + model expansion + root fix
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) <noreply@anthropic.com>
This commit is contained in:
Executable
+45
@@ -0,0 +1,45 @@
|
||||
from backend.schemas.scan import (
|
||||
ScanCreate,
|
||||
ScanUpdate,
|
||||
ScanResponse,
|
||||
ScanListResponse,
|
||||
ScanProgress
|
||||
)
|
||||
from backend.schemas.target import (
|
||||
TargetCreate,
|
||||
TargetResponse,
|
||||
TargetBulkCreate,
|
||||
TargetValidation
|
||||
)
|
||||
from backend.schemas.prompt import (
|
||||
PromptCreate,
|
||||
PromptUpdate,
|
||||
PromptResponse,
|
||||
PromptParse,
|
||||
PromptParseResult
|
||||
)
|
||||
from backend.schemas.vulnerability import (
|
||||
VulnerabilityResponse,
|
||||
VulnerabilityTestResponse,
|
||||
VulnerabilityTypeInfo
|
||||
)
|
||||
from backend.schemas.report import (
|
||||
ReportResponse,
|
||||
ReportGenerate
|
||||
)
|
||||
from backend.schemas.agent_task import (
|
||||
AgentTaskCreate,
|
||||
AgentTaskUpdate,
|
||||
AgentTaskResponse,
|
||||
AgentTaskListResponse,
|
||||
AgentTaskSummary
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"ScanCreate", "ScanUpdate", "ScanResponse", "ScanListResponse", "ScanProgress",
|
||||
"TargetCreate", "TargetResponse", "TargetBulkCreate", "TargetValidation",
|
||||
"PromptCreate", "PromptUpdate", "PromptResponse", "PromptParse", "PromptParseResult",
|
||||
"VulnerabilityResponse", "VulnerabilityTestResponse", "VulnerabilityTypeInfo",
|
||||
"ReportResponse", "ReportGenerate",
|
||||
"AgentTaskCreate", "AgentTaskUpdate", "AgentTaskResponse", "AgentTaskListResponse", "AgentTaskSummary"
|
||||
]
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
NeuroSploit v3 - Agent Task Schemas
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class AgentTaskCreate(BaseModel):
|
||||
"""Schema for creating an agent task"""
|
||||
scan_id: str = Field(..., description="Scan ID this task belongs to")
|
||||
task_type: str = Field(..., description="Task type: recon, analysis, testing, reporting")
|
||||
task_name: str = Field(..., description="Human-readable task name")
|
||||
description: Optional[str] = Field(None, description="Task description")
|
||||
tool_name: Optional[str] = Field(None, description="Tool being used")
|
||||
tool_category: Optional[str] = Field(None, description="Tool category")
|
||||
|
||||
|
||||
class AgentTaskUpdate(BaseModel):
|
||||
"""Schema for updating an agent task"""
|
||||
status: Optional[str] = Field(None, description="Task status")
|
||||
items_processed: Optional[int] = Field(None, description="Items processed")
|
||||
items_found: Optional[int] = Field(None, description="Items found")
|
||||
result_summary: Optional[str] = Field(None, description="Result summary")
|
||||
error_message: Optional[str] = Field(None, description="Error message if failed")
|
||||
|
||||
|
||||
class AgentTaskResponse(BaseModel):
|
||||
"""Schema for agent task response"""
|
||||
id: str
|
||||
scan_id: str
|
||||
task_type: str
|
||||
task_name: str
|
||||
description: Optional[str]
|
||||
tool_name: Optional[str]
|
||||
tool_category: Optional[str]
|
||||
status: str
|
||||
started_at: Optional[datetime]
|
||||
completed_at: Optional[datetime]
|
||||
duration_ms: Optional[int]
|
||||
items_processed: int
|
||||
items_found: int
|
||||
result_summary: Optional[str]
|
||||
error_message: Optional[str]
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class AgentTaskListResponse(BaseModel):
|
||||
"""Schema for list of agent tasks"""
|
||||
tasks: List[AgentTaskResponse]
|
||||
total: int
|
||||
scan_id: str
|
||||
|
||||
|
||||
class AgentTaskSummary(BaseModel):
|
||||
"""Schema for agent task summary statistics"""
|
||||
total: int
|
||||
pending: int
|
||||
running: int
|
||||
completed: int
|
||||
failed: int
|
||||
by_type: dict # recon, analysis, testing, reporting counts
|
||||
by_tool: dict # tool name -> count
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
NeuroSploit v3 - Prompt Schemas
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class PromptCreate(BaseModel):
|
||||
"""Schema for creating a prompt"""
|
||||
name: str = Field(..., max_length=255, description="Prompt name")
|
||||
description: Optional[str] = Field(None, description="Prompt description")
|
||||
content: str = Field(..., min_length=10, description="Prompt content")
|
||||
category: Optional[str] = Field(None, description="Prompt category")
|
||||
|
||||
|
||||
class PromptUpdate(BaseModel):
|
||||
"""Schema for updating a prompt"""
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
content: Optional[str] = None
|
||||
category: Optional[str] = None
|
||||
|
||||
|
||||
class PromptParse(BaseModel):
|
||||
"""Schema for parsing a prompt"""
|
||||
content: str = Field(..., min_length=10, description="Prompt content to parse")
|
||||
|
||||
|
||||
class VulnerabilityTypeExtracted(BaseModel):
|
||||
"""Extracted vulnerability type from prompt"""
|
||||
type: str
|
||||
category: str
|
||||
confidence: float
|
||||
context: Optional[str] = None
|
||||
|
||||
|
||||
class TestingScope(BaseModel):
|
||||
"""Testing scope extracted from prompt"""
|
||||
include_recon: bool = True
|
||||
depth: str = "standard" # quick, standard, thorough, exhaustive
|
||||
max_requests_per_endpoint: Optional[int] = None
|
||||
time_limit_minutes: Optional[int] = None
|
||||
|
||||
|
||||
class PromptParseResult(BaseModel):
|
||||
"""Result of prompt parsing"""
|
||||
vulnerabilities_to_test: List[VulnerabilityTypeExtracted]
|
||||
testing_scope: TestingScope
|
||||
special_instructions: List[str] = []
|
||||
target_filters: dict = {}
|
||||
output_preferences: dict = {}
|
||||
|
||||
|
||||
class PromptResponse(BaseModel):
|
||||
"""Schema for prompt response"""
|
||||
id: str
|
||||
name: str
|
||||
description: Optional[str]
|
||||
content: str
|
||||
is_preset: bool
|
||||
category: Optional[str]
|
||||
parsed_vulnerabilities: List
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PromptPreset(BaseModel):
|
||||
"""Schema for preset prompt"""
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
category: str
|
||||
vulnerability_count: int
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
NeuroSploit v3 - Report Schemas
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ReportGenerate(BaseModel):
|
||||
"""Schema for generating a report"""
|
||||
scan_id: str = Field(..., description="Scan ID to generate report for")
|
||||
format: str = Field("html", description="Report format: html, pdf, json")
|
||||
title: Optional[str] = Field(None, description="Custom report title")
|
||||
include_executive_summary: bool = Field(True, description="Include executive summary")
|
||||
include_poc: bool = Field(True, description="Include proof of concept")
|
||||
include_remediation: bool = Field(True, description="Include remediation steps")
|
||||
preferred_provider: Optional[str] = Field(None, description="Preferred LLM provider for AI report generation")
|
||||
preferred_model: Optional[str] = Field(None, description="Preferred model for AI report generation")
|
||||
|
||||
|
||||
class ReportResponse(BaseModel):
|
||||
"""Schema for report response"""
|
||||
id: str
|
||||
scan_id: str
|
||||
title: Optional[str]
|
||||
format: str
|
||||
file_path: Optional[str]
|
||||
executive_summary: Optional[str]
|
||||
auto_generated: bool = False
|
||||
is_partial: bool = False
|
||||
generated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ReportListResponse(BaseModel):
|
||||
"""Schema for list of reports"""
|
||||
reports: List[ReportResponse]
|
||||
total: int
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
NeuroSploit v3 - Scan Schemas
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class AuthConfig(BaseModel):
|
||||
"""Authentication configuration for authenticated testing"""
|
||||
auth_type: str = Field("none", description="Auth type: none, cookie, header, basic, bearer")
|
||||
cookie: Optional[str] = Field(None, description="Session cookie value")
|
||||
bearer_token: Optional[str] = Field(None, description="Bearer/JWT token")
|
||||
username: Optional[str] = Field(None, description="Username for basic auth")
|
||||
password: Optional[str] = Field(None, description="Password for basic auth")
|
||||
header_name: Optional[str] = Field(None, description="Custom header name")
|
||||
header_value: Optional[str] = Field(None, description="Custom header value")
|
||||
|
||||
|
||||
class ScanCreate(BaseModel):
|
||||
"""Schema for creating a new scan"""
|
||||
name: Optional[str] = Field(None, max_length=255, description="Scan name")
|
||||
targets: List[str] = Field(..., min_length=1, description="List of target URLs")
|
||||
scan_type: str = Field("full", description="Scan type: quick, full, custom")
|
||||
recon_enabled: bool = Field(True, description="Enable reconnaissance phase")
|
||||
custom_prompt: Optional[str] = Field(None, max_length=32000, description="Custom prompt (up to 32k tokens)")
|
||||
prompt_id: Optional[str] = Field(None, description="ID of preset prompt to use")
|
||||
config: dict = Field(default_factory=dict, description="Additional configuration")
|
||||
auth: Optional[AuthConfig] = Field(None, description="Authentication configuration")
|
||||
custom_headers: Optional[dict] = Field(None, description="Custom HTTP headers to include")
|
||||
|
||||
|
||||
class ScanUpdate(BaseModel):
|
||||
"""Schema for updating a scan"""
|
||||
name: Optional[str] = None
|
||||
status: Optional[str] = None
|
||||
progress: Optional[int] = None
|
||||
current_phase: Optional[str] = None
|
||||
error_message: Optional[str] = None
|
||||
|
||||
|
||||
class ScanProgress(BaseModel):
|
||||
"""Schema for scan progress updates"""
|
||||
scan_id: str
|
||||
status: str
|
||||
progress: int
|
||||
current_phase: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
total_endpoints: int = 0
|
||||
total_vulnerabilities: int = 0
|
||||
|
||||
|
||||
class ScanResponse(BaseModel):
|
||||
"""Schema for scan response"""
|
||||
id: str
|
||||
name: Optional[str]
|
||||
status: str
|
||||
scan_type: str
|
||||
recon_enabled: bool
|
||||
progress: int
|
||||
current_phase: Optional[str]
|
||||
config: dict
|
||||
custom_prompt: Optional[str]
|
||||
prompt_id: Optional[str]
|
||||
auth_type: Optional[str] = None
|
||||
custom_headers: Optional[dict] = None
|
||||
created_at: datetime
|
||||
started_at: Optional[datetime]
|
||||
completed_at: Optional[datetime]
|
||||
error_message: Optional[str]
|
||||
total_endpoints: int
|
||||
total_vulnerabilities: int
|
||||
critical_count: int
|
||||
high_count: int
|
||||
medium_count: int
|
||||
low_count: int
|
||||
info_count: int
|
||||
targets: List[dict] = []
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ScanListResponse(BaseModel):
|
||||
"""Schema for list of scans"""
|
||||
scans: List[ScanResponse]
|
||||
total: int
|
||||
page: int = 1
|
||||
per_page: int = 10
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
NeuroSploit v3 - Target Schemas
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
import re
|
||||
|
||||
|
||||
class TargetCreate(BaseModel):
|
||||
"""Schema for creating a target"""
|
||||
url: str = Field(..., description="Target URL")
|
||||
|
||||
@field_validator('url')
|
||||
@classmethod
|
||||
def validate_url(cls, v: str) -> str:
|
||||
"""Validate URL format"""
|
||||
v = v.strip()
|
||||
if not v:
|
||||
raise ValueError("URL cannot be empty")
|
||||
# Basic URL validation
|
||||
url_pattern = re.compile(
|
||||
r'^https?://' # http:// or https://
|
||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' # domain
|
||||
r'localhost|' # localhost
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # or ip
|
||||
r'(?::\d+)?' # optional port
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
if not url_pattern.match(v):
|
||||
# Try adding https:// prefix
|
||||
if url_pattern.match(f"https://{v}"):
|
||||
return f"https://{v}"
|
||||
raise ValueError(f"Invalid URL format: {v}")
|
||||
return v
|
||||
|
||||
|
||||
class TargetBulkCreate(BaseModel):
|
||||
"""Schema for bulk target creation"""
|
||||
urls: List[str] = Field(..., min_length=1, description="List of URLs")
|
||||
|
||||
@field_validator('urls')
|
||||
@classmethod
|
||||
def validate_urls(cls, v: List[str]) -> List[str]:
|
||||
"""Validate and clean URLs"""
|
||||
cleaned = []
|
||||
url_pattern = re.compile(
|
||||
r'^https?://'
|
||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'
|
||||
r'localhost|'
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
|
||||
r'(?::\d+)?'
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
|
||||
for url in v:
|
||||
url = url.strip()
|
||||
if not url:
|
||||
continue
|
||||
if url_pattern.match(url):
|
||||
cleaned.append(url)
|
||||
elif url_pattern.match(f"https://{url}"):
|
||||
cleaned.append(f"https://{url}")
|
||||
|
||||
if not cleaned:
|
||||
raise ValueError("No valid URLs provided")
|
||||
return cleaned
|
||||
|
||||
|
||||
class TargetValidation(BaseModel):
|
||||
"""Schema for URL validation result"""
|
||||
url: str
|
||||
valid: bool
|
||||
normalized_url: Optional[str] = None
|
||||
hostname: Optional[str] = None
|
||||
port: Optional[int] = None
|
||||
protocol: Optional[str] = None
|
||||
error: Optional[str] = None
|
||||
|
||||
|
||||
class TargetResponse(BaseModel):
|
||||
"""Schema for target response"""
|
||||
id: str
|
||||
scan_id: str
|
||||
url: str
|
||||
hostname: Optional[str]
|
||||
port: Optional[int]
|
||||
protocol: Optional[str]
|
||||
path: Optional[str]
|
||||
status: str
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
NeuroSploit v3 - Vulnerability Schemas
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class VulnerabilityTestResponse(BaseModel):
|
||||
"""Schema for vulnerability test response"""
|
||||
id: str
|
||||
scan_id: str
|
||||
endpoint_id: Optional[str]
|
||||
vulnerability_type: str
|
||||
payload: Optional[str]
|
||||
request_data: dict
|
||||
response_data: dict
|
||||
is_vulnerable: bool
|
||||
confidence: Optional[float]
|
||||
evidence: Optional[str]
|
||||
tested_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class VulnerabilityResponse(BaseModel):
|
||||
"""Schema for vulnerability response"""
|
||||
id: str
|
||||
scan_id: str
|
||||
test_id: Optional[str]
|
||||
title: str
|
||||
vulnerability_type: str
|
||||
severity: str
|
||||
cvss_score: Optional[float]
|
||||
cvss_vector: Optional[str]
|
||||
cwe_id: Optional[str]
|
||||
description: Optional[str]
|
||||
affected_endpoint: Optional[str]
|
||||
poc_request: Optional[str]
|
||||
poc_response: Optional[str]
|
||||
poc_payload: Optional[str]
|
||||
impact: Optional[str]
|
||||
remediation: Optional[str]
|
||||
references: List
|
||||
ai_analysis: Optional[str]
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class VulnerabilityTypeInfo(BaseModel):
|
||||
"""Information about a vulnerability type"""
|
||||
type: str
|
||||
name: str
|
||||
category: str
|
||||
description: str
|
||||
severity_range: str # "medium-critical"
|
||||
owasp_category: Optional[str] = None
|
||||
cwe_ids: List[str] = []
|
||||
|
||||
|
||||
class VulnerabilitySummary(BaseModel):
|
||||
"""Summary of vulnerabilities for dashboard"""
|
||||
total: int = 0
|
||||
critical: int = 0
|
||||
high: int = 0
|
||||
medium: int = 0
|
||||
low: int = 0
|
||||
info: int = 0
|
||||
by_type: dict = {}
|
||||
Reference in New Issue
Block a user