mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-10-18 13:41:32 +02:00
- Graph tab: sidebar with per-finding filter + Overview; description panel shows finding details when selected; walk-based subgraph isolation - Settings: single Config button opens modal with all LLM providers; removed redundant MCP Server card - Issues: colored severity badges (critical/high/medium/low/info) - Sidebar: removed key and terminal icons from footer - Server: cloud environment overrides, vault & guardrails config endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqW6BbQgqGkEDn3RYuCVoM
1179 lines
67 KiB
HTML
1179 lines
67 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>NeuroSploit v4.3.2 — Console</title>
|
||
<link rel="icon" type="image/svg+xml" href="logo.svg">
|
||
<link rel="stylesheet" href="/vendor/xterm.css" />
|
||
<link rel="stylesheet" href="/style.css" />
|
||
</head>
|
||
<body>
|
||
|
||
<button class="sidebar-toggle" id="btnSidebarToggle" title="Show / hide run history" aria-label="Show or hide run history" aria-expanded="false" aria-controls="sidebar">☰</button>
|
||
<div class="sidebar-scrim" id="sidebarScrim" hidden></div>
|
||
|
||
<div class="app">
|
||
|
||
<!-- ============ SIDEBAR ============ -->
|
||
<aside class="sidebar" id="sidebar">
|
||
<div class="sb-top">
|
||
<div class="brand">
|
||
<svg class="mark" viewBox="0 0 48 48" fill="none" aria-hidden="true">
|
||
<path d="M9 39V11l20 20V11" stroke="currentColor" stroke-width="5.5" stroke-linecap="square" stroke-linejoin="miter"/>
|
||
<path d="M39 9V37" stroke="currentColor" stroke-width="5.5" stroke-linecap="square"/>
|
||
<g stroke="#22a8ff" stroke-width="2.4" fill="#22a8ff">
|
||
<path d="M12 16h7l6 6h8" fill="none"/>
|
||
<circle cx="11" cy="16" r="3.4"/><circle cx="34" cy="22" r="3.4"/>
|
||
<circle cx="38" cy="10" r="3.4"/><circle cx="15" cy="37" r="3.4"/>
|
||
<path d="M18 34l-3 3" fill="none"/>
|
||
</g>
|
||
<path d="M41 7L18 41" stroke="#22a8ff" stroke-width="2.6" stroke-linecap="round"/>
|
||
</svg>
|
||
NeuroSploit
|
||
</div>
|
||
<button class="icon-btn" id="btnThemeToggle" title="Toggle light / dark theme">☾</button>
|
||
</div>
|
||
|
||
<button class="sb-new" id="btnNewEngagement">+ New Pentest</button>
|
||
|
||
<nav class="sb-nav" id="sbNav">
|
||
<button class="sb-nav-item active" data-view="dash"><span class="sb-nav-icon">▤</span> Dashboard</button>
|
||
<button class="sb-nav-item" data-view="pentests"><span class="sb-nav-icon">⊞</span> Pentests</button>
|
||
<button class="sb-nav-item" data-view="prreviews"><span class="sb-nav-icon">⎇</span> PR Reviews</button>
|
||
<button class="sb-nav-item" data-view="issues"><span class="sb-nav-icon">⚑</span> Issues</button>
|
||
<div class="sb-nav-separator"></div>
|
||
<button class="sb-nav-item" data-view="repos"><span class="sb-nav-icon">◎</span> Repositories</button>
|
||
<button class="sb-nav-item" data-view="domains"><span class="sb-nav-icon">◇</span> Domains</button>
|
||
<button class="sb-nav-item" data-view="networks"><span class="sb-nav-icon">⬡</span> Networks</button>
|
||
<div class="sb-nav-separator"></div>
|
||
<button class="sb-nav-item" data-view="vault"><span class="sb-nav-icon">🔑</span> Vault</button>
|
||
<button class="sb-nav-item" data-view="guardrails"><span class="sb-nav-icon">⛨</span> Guardrails</button>
|
||
<div class="sb-nav-separator"></div>
|
||
<button class="sb-nav-item" id="sbTerminal"><span class="sb-nav-icon">❭_</span> Terminal</button>
|
||
<button class="sb-nav-item" data-view="integrations"><span class="sb-nav-icon">⚙</span> Integrations</button>
|
||
<button class="sb-nav-item" data-view="settings"><span class="sb-nav-icon">☰</span> Settings</button>
|
||
</nav>
|
||
|
||
<div class="sb-run-history" id="sbRunHistory">
|
||
<div class="sb-search">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="runFilter" type="text" autocomplete="off" placeholder="Filter runs" aria-label="Filter runs" />
|
||
</div>
|
||
|
||
<div class="sb-groups" id="sbGroups"><!-- populated by app.js --></div>
|
||
</div>
|
||
|
||
<div class="sb-bottom">
|
||
<span class="sb-version" id="sbVersion">v4.3.2</span>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ============ MAIN ============ -->
|
||
<main class="main">
|
||
|
||
<!-- ============ DASHBOARD ============ -->
|
||
<section class="dashboard" id="dashView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Dashboard</div>
|
||
<div class="topbar-sub">Coverage, findings and FAIR loss exposure across every run</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<select id="dashRange" class="dash-range" title="Time range">
|
||
<option value="0">all time</option>
|
||
<option value="7">last 7 days</option>
|
||
<option value="30">last 30 days</option>
|
||
<option value="90">last 90 days</option>
|
||
</select>
|
||
<button class="btn" id="btnDashRefresh">Refresh</button>
|
||
</header>
|
||
<div class="dash-body" id="dashBody">
|
||
<div class="empty-state">Loading…</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ PENTESTS ============ -->
|
||
<section class="page-view" id="pentestsView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Pentests</div>
|
||
<div class="topbar-sub">All engagements — black-box, white-box, greybox, host, AI, mobile, container</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<input type="text" id="pentestSearch" class="topbar-search" placeholder="Search pentests…" />
|
||
<button class="btn btn-accent" id="btnNewPentest2">+ New Pentest</button>
|
||
</header>
|
||
<div class="page-body" id="pentestsBody"><div class="empty-state">Loading…</div></div>
|
||
</section>
|
||
|
||
<!-- ============ PR REVIEWS ============ -->
|
||
<section class="page-view" id="prreviewsView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">PR Reviews</div>
|
||
<div class="topbar-sub">Security reviews of pull requests</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn btn-accent" id="btnNewPrReview">+ New Review</button>
|
||
</header>
|
||
<div class="page-body" id="prreviewsBody"><div class="empty-state">No PR reviews yet. Run <code>neurosploit pr owner/repo 123</code> or use the MCP server.</div></div>
|
||
</section>
|
||
|
||
<!-- ============ ISSUES ============ -->
|
||
<section class="page-view" id="issuesView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Issues</div>
|
||
<div class="topbar-sub">All findings across every engagement</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<select id="issuesSevFilter" class="dash-range">
|
||
<option value="">All severities</option>
|
||
<option value="critical">Critical</option>
|
||
<option value="high">High</option>
|
||
<option value="medium">Medium</option>
|
||
<option value="low">Low</option>
|
||
</select>
|
||
<select id="issuesStatusFilter" class="dash-range">
|
||
<option value="">All statuses</option>
|
||
<option value="open">Open</option>
|
||
<option value="fixed">Fixed</option>
|
||
</select>
|
||
<input type="text" id="issuesSearch" class="topbar-search" placeholder="Search issues…" />
|
||
</header>
|
||
<div class="page-body" id="issuesBody"><div class="empty-state">Loading…</div></div>
|
||
</section>
|
||
|
||
<!-- ============ REPOSITORIES ============ -->
|
||
<section class="page-view" id="reposView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Repositories</div>
|
||
<div class="topbar-sub">Connected source repositories for white-box, greybox, and PR reviews</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn btn-accent" id="btnAddRepo">+ Add Repository</button>
|
||
</header>
|
||
<div class="page-body" id="reposBody"><div class="empty-state">No repositories connected yet.</div></div>
|
||
</section>
|
||
|
||
<!-- ============ DOMAINS ============ -->
|
||
<section class="page-view" id="domainsView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Domains</div>
|
||
<div class="topbar-sub">Target domains and subdomains for black-box engagements</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn btn-accent" id="btnAddDomain">+ Add Domain</button>
|
||
</header>
|
||
<div class="page-body" id="domainsBody"><div class="empty-state">No domains configured yet.</div></div>
|
||
</section>
|
||
|
||
<!-- ============ NETWORKS ============ -->
|
||
<section class="page-view" id="networksView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Networks</div>
|
||
<div class="topbar-sub">Network ranges and hosts for infrastructure scanning</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn btn-accent" id="btnAddNetwork">+ Add Network</button>
|
||
</header>
|
||
<div class="page-body" id="networksBody"><div class="empty-state">No networks configured yet.</div></div>
|
||
</section>
|
||
|
||
<!-- ============ VAULT ============ -->
|
||
<section class="page-view" id="vaultView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Vault</div>
|
||
<div class="topbar-sub">Target authentication, credentials files, and API collections</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
</header>
|
||
<div class="page-body" id="vaultBody">
|
||
<div class="config-grid">
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-title">Target Authentication</div>
|
||
<div class="config-card-desc">Credentials used so agents test as a logged-in user. Kept only for this session.</div>
|
||
<div class="form-group">
|
||
<label for="vaultAuthHeader">Auth header</label>
|
||
<input id="vaultAuthHeader" type="text" placeholder="Authorization: Bearer <token> or Cookie: session=..." />
|
||
<div class="field-help">Sent to the CLI as an ephemeral creds file.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Named roles (multi-identity access-control testing)</label>
|
||
<div class="role-list" id="vaultRoleList"></div>
|
||
<button class="btn btn-sm" id="btnVaultAddRole" style="align-self:flex-start;">+ Add role</button>
|
||
<div class="field-help">Two or more roles enable IDOR/BOLA/BFLA cross-role testing.</div>
|
||
</div>
|
||
</div>
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-title">Credentials File</div>
|
||
<div class="form-group">
|
||
<label for="vaultCredsPath">creds.yaml path (overrides target auth above)</label>
|
||
<input id="vaultCredsPath" type="text" placeholder="creds.yaml" />
|
||
<div class="field-help">An explicit file on disk — see neurosploit-rs/creds.example.yaml for the schema.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="vaultCollectionFile">API collection (Postman / OpenAPI / Swagger / HAR)</label>
|
||
<input id="vaultCollectionFile" type="file" accept=".json,application/json,.har" multiple />
|
||
<input id="vaultCollectionPath" type="text" placeholder="…or a path on disk: file.json or a directory of .json files" />
|
||
<div class="field-help">Imports endpoints as known surface — file or directory of .json files.</div>
|
||
</div>
|
||
</div>
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-actions"><button class="btn btn-accent" id="btnVaultSave">Save</button></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ GUARDRAILS ============ -->
|
||
<section class="page-view" id="guardrailsView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Guardrails</div>
|
||
<div class="topbar-sub">Authorization, scoping, safety controls, environment, and egress configuration</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
</header>
|
||
<div class="page-body" id="guardrailsBody">
|
||
<div class="config-grid">
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-title">Capability Token</div>
|
||
<div class="form-group">
|
||
<label for="grCapToken">Capability token</label>
|
||
<input id="grCapToken" type="text" placeholder="ns-cap.v1.…" spellcheck="false" />
|
||
<div class="field-status" id="grCapStatus"></div>
|
||
<div class="field-help">Signed grant for this engagement: who authorized it, which hosts, which environment, until when. Verified by the harness. Mint with <code>neurosploit capability issue</code>.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grInScope">Additional authorized hosts</label>
|
||
<input id="grInScope" type="text" placeholder="app.example.com, *.api.example.com, 10.0.0.0/24" />
|
||
<div class="field-help">Without this the engagement is authorized against the target and nothing else.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-title">Scoping & Guardrails <span class="pill" style="font-size:10px;">enforced in code</span></div>
|
||
<div class="config-card-desc">The hard scope is the boundary: a request whose host is not listed is refused before it is sent. Exclusions always win. A capability token still caps all of this.</div>
|
||
<div class="form-group">
|
||
<label for="grScopeHard">Hard scope — the allowlist</label>
|
||
<textarea id="grScopeHard" rows="3" placeholder="one per line, or comma-separated app.example.com *.staging.example.com"></textarea>
|
||
<div class="field-help">Exact host · <code>*.wildcard</code> · <code>CIDR</code> · <code>https://host/path</code> prefix. Empty = nothing extra enforced.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="form-group">
|
||
<label for="grScopeExclude">Exclusions — always win</label>
|
||
<textarea id="grScopeExclude" rows="3" placeholder="payments.example.com admin.example.com"></textarea>
|
||
<div class="field-help">Refused even if the allowlist would cover them.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grScopeObserve">Observe-only</label>
|
||
<textarea id="grScopeObserve" rows="3" placeholder="cdn.example.com *.thirdparty.example.com"></textarea>
|
||
<div class="field-help">May be looked at (recon) but never attacked.</div>
|
||
</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="form-group">
|
||
<label>State-changing methods</label>
|
||
<div class="check-row"><input type="checkbox" id="grDestructive" /> <label for="grDestructive">Allow DELETE / PUT / PATCH</label></div>
|
||
<div class="field-help">Off by default — a scan should not change the target's state.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Test accounts</label>
|
||
<div class="check-row"><input type="checkbox" id="grAccounts" checked /> <label for="grAccounts">Allow account creation</label></div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grMaxAccounts">Max accounts</label>
|
||
<input class="narrow" id="grMaxAccounts" type="number" min="0" value="3" />
|
||
<div class="field-help">0 = unlimited.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grRate">Requests / min</label>
|
||
<input class="narrow" id="grRate" type="number" min="0" value="240" />
|
||
<div class="field-help">Whole engagement. 0 = unlimited.</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grForbidden">Forbidden payloads</label>
|
||
<textarea id="grForbidden" rows="2" placeholder="delete from drop table rm -rf /"></textarea>
|
||
<div class="field-help">Substrings NEVER acceptable. Extends built-in defaults.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grNotes">Notes — guidance, NOT enforced</label>
|
||
<textarea id="grNotes" rows="2" placeholder="SOW-2026-0142; test window 02:00–06:00 UTC"></textarea>
|
||
<div class="field-help">Context passed to agents. Prose is not a control.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-title">Environment & Policy</div>
|
||
<div class="field-row">
|
||
<div class="form-group">
|
||
<label for="grEnv">Environment</label>
|
||
<select id="grEnv">
|
||
<option value="production" selected>production</option>
|
||
<option value="staging">staging</option>
|
||
<option value="development">development</option>
|
||
<option value="lab">lab</option>
|
||
<option value="ot-production">ot-production (ICS/SCADA)</option>
|
||
</select>
|
||
<div class="field-help">Scales every risk score.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grPolicy">Policy profile</label>
|
||
<select id="grPolicy">
|
||
<option value="web" selected>web — standard</option>
|
||
<option value="ot">ot — read-only, paced, industrial writes blocked</option>
|
||
</select>
|
||
<div class="field-help">OT blocks writes, disruptive actions, fuzzing and exploit payloads over industrial protocols.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-title">Egress & Out-of-band</div>
|
||
<div class="form-group">
|
||
<label for="grTransport">Transport (how traffic reaches the target)</label>
|
||
<input id="grTransport" type="text" placeholder="direct · socks5://127.0.0.1:1080 · openvpn:/path/client.ovpn" spellcheck="false" />
|
||
<div class="field-help">An internal target with no transport is refused, not tested.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="form-group">
|
||
<label for="grOobDomain">Out-of-band domain</label>
|
||
<input id="grOobDomain" type="text" placeholder="oob.yourdomain.com" spellcheck="false" />
|
||
<div class="field-help">Without it blind SSRF/XXE/RCE can only be reported as leads.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grOobHttp">OOB HTTP listener</label>
|
||
<input id="grOobHttp" type="text" placeholder="0.0.0.0:8080" spellcheck="false" />
|
||
<div class="field-help">Where callbacks land.</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grOobDns">OOB DNS listener</label>
|
||
<input id="grOobDns" type="text" placeholder="0.0.0.0:5353" spellcheck="false" />
|
||
<div class="field-help">Only if the zone is delegated here.</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="grSms">Inbound SMS (OTP & rate-limit work)</label>
|
||
<input id="grSms" type="text" placeholder="twilio:<sid>:<token>:+15550101 · webhook:https://…/inbox:+15550101" spellcheck="false" />
|
||
<div class="field-help">A throttling claim counts delivered messages carrying distinct codes, not HTTP 200s.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-card" style="grid-column:1/-1;">
|
||
<div class="config-card-actions"><button class="btn btn-accent" id="btnGuardrailsSave">Save</button></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ INTEGRATIONS ============ -->
|
||
<section class="page-view" id="integrationsView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Integrations</div>
|
||
<div class="topbar-sub">Connect external services — GitHub, GitLab, Jira, Slack, CI/CD, AWS, GCP, Azure</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
</header>
|
||
<div class="page-body" id="integrationsBody"><div class="empty-state">Loading…</div></div>
|
||
</section>
|
||
|
||
<!-- ============ SETTINGS ============ -->
|
||
<section class="page-view" id="settingsView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Settings</div>
|
||
<div class="topbar-sub">Console configuration, LLM provider keys, and preferences</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
</header>
|
||
<div class="page-body" id="settingsBody"><div class="empty-state">Loading…</div></div>
|
||
</section>
|
||
|
||
<!-- ============ WIZARD (new engagement) ============ -->
|
||
<section class="wizard" id="wizardView">
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">New Pentest</div>
|
||
<div class="topbar-sub">Asset → Scope & Auth → Leads → Model & Run → Review</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn" id="btnOpenTerm2">❭_ Terminal</button>
|
||
<button class="btn" id="btnOpenAuth2">🔑 Auth & Keys</button>
|
||
</header>
|
||
|
||
<nav class="stepper" id="stepper">
|
||
<button class="step-tab active" data-step="0"><span class="n">1</span> Asset</button>
|
||
<button class="step-tab" data-step="1"><span class="n">2</span> Scope & Auth</button>
|
||
<button class="step-tab" data-step="2"><span class="n">3</span> Leads</button>
|
||
<button class="step-tab" data-step="3"><span class="n">4</span> Model & Run</button>
|
||
<button class="step-tab" data-step="4"><span class="n">5</span> Review</button>
|
||
</nav>
|
||
|
||
<div class="wizard-body">
|
||
|
||
<!-- Step 1 — Asset -->
|
||
<div class="wizard-panel" data-panel="0">
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldName">Engagement name</label>
|
||
<input id="fieldName" type="text" placeholder="e.g. Keystone – Digital Banking" aria-describedby="errName" />
|
||
<div class="field-error" id="errName" hidden></div>
|
||
<div class="field-help">Identifies this engagement in the sidebar and run history — required.</div>
|
||
</div>
|
||
<div>
|
||
<div class="section-title">What are you testing?</div>
|
||
<div class="section-desc">Pick the engagement type — this decides which CLI subcommand runs underneath.</div>
|
||
</div>
|
||
<div class="mode-tiles" id="modeTiles">
|
||
<button class="mode-tile" data-mode="run"><span class="t">Black-box</span><span class="d">URL only — recon-driven</span></button>
|
||
<button class="mode-tile" data-mode="whitebox"><span class="t">White-box</span><span class="d">Source repo — SAST agents</span></button>
|
||
<button class="mode-tile" data-mode="greybox"><span class="t">Grey-box</span><span class="d">URL + source together</span></button>
|
||
<button class="mode-tile" data-mode="host"><span class="t">Host / Infra</span><span class="d">IP — Linux/Windows/AD</span></button>
|
||
<button class="mode-tile" data-mode="aitest"><span class="t">AI / LLM</span><span class="d">Live AI agent or MCP endpoint</span></button>
|
||
<button class="mode-tile" data-mode="cloud"><span class="t">Cloud</span><span class="d">AWS / GCP / Azure audit</span></button>
|
||
</div>
|
||
|
||
<div class="field-group" id="fieldTargetGroup">
|
||
<label class="field-label" id="targetLabel" for="fieldTarget">Target URL</label>
|
||
<input id="fieldTarget" type="text" placeholder="https://target.example.com" aria-describedby="errTarget" />
|
||
<div class="field-error" id="errTarget" hidden></div>
|
||
<div class="field-help" id="targetHelp">The application, host, or endpoint to test.</div>
|
||
</div>
|
||
<div class="field-group" id="fieldRepoGroup" hidden>
|
||
<label class="field-label" for="fieldRepo">Source repo</label>
|
||
<input id="fieldRepo" type="text" placeholder="owner/repo, a GitHub URL, or a local path" aria-describedby="errRepo" />
|
||
<div class="field-error" id="errRepo" hidden></div>
|
||
<div class="field-help">Cloned automatically if it's a GitHub URL or owner/repo shorthand.</div>
|
||
</div>
|
||
<div class="field-group" id="fieldCloudGroup" hidden>
|
||
<label class="field-label">Connected cloud</label>
|
||
<select id="fieldCloudProvider" class="narrow">
|
||
<option value="">Select a cloud provider…</option>
|
||
</select>
|
||
<div class="field-help">Pick a connected cloud integration from the Integrations page. Configure credentials there first.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2 — Scope & Auth -->
|
||
<div class="wizard-panel" data-panel="1" hidden>
|
||
<div>
|
||
<div class="section-title">Objective & focus</div>
|
||
<div class="section-desc">Steers what the agents prioritise and what counts as impact.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldObjective">Objective</label>
|
||
<textarea id="fieldObjective" placeholder="e.g. Pre-launch review of the checkout flow — prove any path to unauthorized order access."></textarea>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldFocus">Focus</label>
|
||
<textarea id="fieldFocus" placeholder="e.g. Prioritize the paths most likely to cause data leakage."></textarea>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldClasses">Focus vuln classes <span class="req">— optional</span></label>
|
||
<input id="fieldClasses" type="text" placeholder="idor, sqli, xss, ssrf — pins the matching agents, skips recon-driven selection" />
|
||
<div class="field-help">Same as the CLI <code>--class</code> / REPL <code>/class</code>. Leave empty for recon-driven selection.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldOutOfScope">Out of scope</label>
|
||
<textarea id="fieldOutOfScope" placeholder="Hosts, paths, or techniques the agents must not touch."></textarea>
|
||
</div>
|
||
<div>
|
||
<div class="section-title">Authentication</div>
|
||
<div class="section-desc">Test as a logged-in user. Configured in the <button class="btn btn-sm" id="btnOpenAuth3">🔑 Auth & Keys</button> menu.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 3 — Leads -->
|
||
<div class="wizard-panel wizard-panel-wide" data-panel="2" hidden>
|
||
<div>
|
||
<div class="section-title">Set the action plan</div>
|
||
<div class="section-desc">Toggle specific leads to test, or leave everything off to let recon-driven auto-selection choose.</div>
|
||
</div>
|
||
<div class="lead-toolbar">
|
||
<select class="input-sm" id="catFilter" title="Show one category"><option value="">All categories</option></select>
|
||
<div class="search-wrap">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="leadSearch" type="text" placeholder="Search leads by name or CWE" />
|
||
</div>
|
||
<div class="chips">
|
||
<button class="chip chip-active" data-filter="all">All <span id="chipAll">0</span></button>
|
||
<button class="chip" data-filter="selected">Pinned <span id="chipSelected">0</span></button>
|
||
<button class="chip" data-filter="excluded">Not pinned <span id="chipExcluded">0</span></button>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn btn-sm" id="btnExpandAll">Expand all</button>
|
||
<button class="btn btn-sm" id="btnSelectAll">Select all</button>
|
||
<button class="btn btn-sm" id="btnClearAll">Clear all</button>
|
||
<button class="btn btn-sm" id="btnCustomLead">+ Custom lead</button>
|
||
</div>
|
||
<div class="field-help lead-tip">Categories start collapsed — click one to open it, or click its switch to pin every lead inside at once.</div>
|
||
<div class="custom-leads" id="customLeadsList" hidden></div>
|
||
<div class="categories" id="categories"><!-- populated --></div>
|
||
<div class="empty-state" id="leadsEmpty" hidden>No lead matches that search.</div>
|
||
</div>
|
||
|
||
<!-- Step 4 — Model & Run -->
|
||
<div class="wizard-panel" data-panel="3" hidden>
|
||
<div>
|
||
<div class="section-title">Model</div>
|
||
<div class="section-desc">Pick a provider and model from the harness's live catalog.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldProvider">Provider</label>
|
||
<select id="fieldProvider"></select>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldModelSelect">Model</label>
|
||
<select id="fieldModelSelect"></select>
|
||
</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Auth mode</label>
|
||
<div class="auth-mode-toggle" id="authModeToggle">
|
||
<button data-mode="api" class="selected">API key</button>
|
||
<button data-mode="subscription">Subscription (local CLI login)</button>
|
||
</div>
|
||
<div class="field-help" id="authModeHelp">Uses the API key set in Auth & Keys for this provider.</div>
|
||
</div>
|
||
<div class="check-row"><input type="checkbox" id="fieldMcp" /> <label for="fieldMcp">Playwright MCP (browser tool access, subscription backends only)</label></div>
|
||
|
||
<div>
|
||
<div class="section-title">Run settings</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group"><label class="field-label" for="fieldVotes">Votes</label><input class="narrow" id="fieldVotes" type="number" min="1" max="9" value="3" /><div class="field-help">Models that must agree before a finding is kept.</div></div>
|
||
<div class="field-group"><label class="field-label" for="fieldChain">Chain depth</label><input class="narrow" id="fieldChain" type="number" min="0" max="5" value="2" /><div class="field-help">How far findings get chained into attack paths.</div></div>
|
||
<div class="field-group"><label class="field-label" for="fieldRecon">Recon intensity</label>
|
||
<select class="narrow" id="fieldRecon">
|
||
<option value="1">1 · quick</option>
|
||
<option value="2">2 · standard</option>
|
||
<option value="3" selected>3 · deep</option>
|
||
<option value="4">4 · exhaustive</option>
|
||
</select>
|
||
<div class="field-help">Deeper recon finds more surface but costs more tokens.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="section-title">Reasoning budget</div>
|
||
<div class="section-desc">Optional. Left on <em>unlimited</em>, the run behaves exactly as it always has — full depth, no cap.</div>
|
||
</div>
|
||
<div class="check-col">
|
||
<div class="check-row"><input type="checkbox" id="fieldResearch" /> <label for="fieldResearch"><b>🔬 Research mode</b> — hunt a novel, CVE-reportable bug (whitebox/greybox)</label></div>
|
||
<div class="field-help check-help">Known-CVE de-dup + patch-diff variant analysis. Best with a source repo; reports only genuinely new issues (or a concrete patch bypass).</div>
|
||
<div class="check-row check-quick"><input type="checkbox" id="fieldQuick" /> <label for="fieldQuick"><b>⚡ Quick mode</b> — short, low-cost test</label></div>
|
||
<div class="field-help check-help">Economy preset: 1 voter, 1 chain round, light recon, ≤6 agents, eco budget. The big token saver. Wins over the settings below.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group"><label class="field-label" for="fieldBudget">Budget mode</label>
|
||
<select class="narrow" id="fieldBudget">
|
||
<option value="unlimited" selected>unlimited · full run (default)</option>
|
||
<option value="eco">eco · cover ground, reason only on strong signal</option>
|
||
<option value="balanced">balanced · investigate what looks suspicious</option>
|
||
<option value="aggressive">aggressive · multiple hypotheses, deep validation</option>
|
||
</select>
|
||
<div class="field-help">How compute is spent, not how much there is.</div>
|
||
</div>
|
||
<div class="field-group"><label class="field-label" for="fieldTokenLimit">Token limit</label><input class="narrow" id="fieldTokenLimit" type="number" min="0" step="10000" placeholder="none" /><div class="field-help">Hard ceiling for the run. Empty or 0 = none.</div></div>
|
||
<div class="field-group"><label class="field-label" for="fieldOrder">Order</label>
|
||
<select class="narrow" id="fieldOrder">
|
||
<option value="coverage-first" selected>coverage-first</option>
|
||
<option value="depth-first">depth-first</option>
|
||
</select>
|
||
<div class="field-help">Map everything first, or chase a lead as it appears.</div>
|
||
</div>
|
||
<div class="field-group"><label class="field-label" for="fieldSampleRoute">Sample / route</label><input class="narrow" id="fieldSampleRoute" type="number" min="1" max="50" value="3" /><div class="field-help">Requests per endpoint family (<code>/api/users/{id}</code> is sampled, not enumerated).</div></div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="section-title">Tooling & assurance</div>
|
||
<div class="section-desc">Optional. Route through a proxy, run in a container, re-check every PoC, and frame findings against a compliance framework.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group"><label class="field-label" for="fieldIntercept">Intercepting proxy</label>
|
||
<select class="narrow" id="fieldIntercept">
|
||
<option value="off" selected>off · direct</option>
|
||
<option value="own">NeuroSploit Interceptor (record + passive discovery)</option>
|
||
<option value="burp">Burp Suite</option>
|
||
<option value="caido">Caido</option>
|
||
<option value="zap">OWASP ZAP</option>
|
||
<option value="mitmproxy">mitmproxy</option>
|
||
<option value="own+burp">NeuroSploit Interceptor + Burp</option>
|
||
<option value="own+caido">NeuroSploit Interceptor + Caido</option>
|
||
</select>
|
||
<div class="field-help">The harness and agent commands route through it. Full HTTPS interception needs one of the tools (own tunnels TLS).</div>
|
||
</div>
|
||
<div class="field-group"><label class="field-label" for="fieldSandbox">Sandbox</label>
|
||
<select class="narrow" id="fieldSandbox">
|
||
<option value="" selected>host (no container)</option>
|
||
<option value="default">Kali container (kalilinux/kali-rolling)</option>
|
||
</select>
|
||
<div class="field-help">Runs attack commands off the host, with the Kali toolbox. Needs docker or podman.</div>
|
||
</div>
|
||
<div class="field-group"><label class="field-label">PoC re-validation</label>
|
||
<div class="check-row"><input type="checkbox" id="fieldRevalidatePoc" /> <label for="fieldRevalidatePoc">Re-run every PoC; demote what no longer reproduces</label></div>
|
||
</div>
|
||
<div class="field-group"><label class="field-label" for="fieldTypesafe">TypeSafe (System One)</label>
|
||
<select class="narrow" id="fieldTypesafe">
|
||
<option value="auto" selected>auto — on if TYPESAFE_API_KEY set</option>
|
||
<option value="on">on — calibrated confirmation + adjudication</option>
|
||
<option value="off">off — same pipeline, no TypeSafe (for A/B)</option>
|
||
</select>
|
||
<div class="field-help">Additional confirmation strategy (Choice/Noul over real replays). Off runs the identical pipeline so you can compare with/without.</div>
|
||
</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Compliance mapping</label>
|
||
<div class="check-row"><input type="checkbox" id="fieldCompPci" value="pci-dss" /> <label for="fieldCompPci">PCI-DSS v4.0</label></div>
|
||
<div class="check-row"><input type="checkbox" id="fieldCompHipaa" value="hipaa" /> <label for="fieldCompHipaa">HIPAA Security Rule</label></div>
|
||
<div class="check-row"><input type="checkbox" id="fieldCompSoc2" value="soc2" /> <label for="fieldCompSoc2">SOC 2 (Trust Services Criteria)</label></div>
|
||
<div class="check-row"><input type="checkbox" id="fieldCompGdpr" value="gdpr" /> <label for="fieldCompGdpr">GDPR (data-protection articles)</label></div>
|
||
<div class="field-help">Maps confirmed findings onto control requirements in the report. Indicates gaps for an assessor — never a compliance verdict.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 5 — Review -->
|
||
<div class="wizard-panel" data-panel="4" hidden>
|
||
<div>
|
||
<div class="section-title">Review</div>
|
||
<div class="section-desc">Confirm before launching — this spawns the real CLI harness.</div>
|
||
</div>
|
||
<div class="review-grid" id="reviewGrid"></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<footer class="wizard-footer">
|
||
<div class="summary-line" id="wizardSummary"></div>
|
||
<div class="footer-actions">
|
||
<button class="btn" id="btnStepBack">← Back</button>
|
||
<button class="btn btn-primary" id="btnStepNext">Next →</button>
|
||
<button class="btn btn-primary" id="btnLaunch" hidden>Start Exploitation →</button>
|
||
</div>
|
||
</footer>
|
||
</section>
|
||
|
||
<!-- ============ LIVE RUN ============ -->
|
||
<section class="runpage" id="liveView" hidden>
|
||
<header class="run-head">
|
||
<div class="run-head-main">
|
||
<div class="run-target" id="liveTarget">—</div>
|
||
<div class="run-meta" id="liveTargetSub"></div>
|
||
<div class="run-meta"><span class="phase-dot" id="phaseDot"></span><span id="livePhase">starting</span></div>
|
||
<div class="run-meta" id="livePinned"></div>
|
||
</div>
|
||
<div class="run-actions">
|
||
<button class="btn" id="btnOpenTerm3">❭_ Terminal</button>
|
||
<a class="btn" id="btnOpenReport" target="_blank" hidden>Open report</a>
|
||
<button class="btn" id="btnPauseRun" title="Hold the run where it is — in-flight agents finish, nothing is lost">⏸ Pause</button>
|
||
<a class="btn" id="btnDownloadLog" download>Download log</a>
|
||
<button class="btn" id="btnReportNow" title="Write the report from what has been found so far">Report so far</button>
|
||
<button class="btn btn-danger" id="btnStopRun">Stop</button>
|
||
<button class="btn" id="btnBackToBoard">← Back</button>
|
||
</div>
|
||
</header>
|
||
<div class="progress-wrap">
|
||
<div class="progress-bar" id="progressBar"><div class="progress-fill" id="progressFill"></div></div>
|
||
<div class="progress-label" id="progressLabel">0 / 0 agents</div>
|
||
</div>
|
||
<div class="agent-panel" id="agentPanel" hidden>
|
||
<div class="agent-panel-head">
|
||
<span>What's being tested</span>
|
||
<span class="agent-legend"><i class="ap running"></i>testing <i class="ap done"></i>done <i class="ap found"></i>found <i class="ap failed"></i>error</span>
|
||
</div>
|
||
<div class="agent-grid" id="agentGrid"></div>
|
||
</div>
|
||
<nav class="run-tabs">
|
||
<button class="run-tab active" data-tab="findings">Findings <span id="liveFindingsCount">0</span></button>
|
||
<button class="run-tab" data-tab="log">Activity log</button>
|
||
</nav>
|
||
<div class="run-body">
|
||
<div class="run-tab-panel" data-tabpanel="findings">
|
||
<div class="findings-toolbar">
|
||
<div class="sev-summary" id="liveSevSummary"></div>
|
||
<div class="topbar-spacer"></div>
|
||
<div class="search-wrap">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="liveFindingSearch" type="text" placeholder="Filter findings" />
|
||
</div>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table class="data-table" id="liveFindingsTable">
|
||
<thead><tr><th data-sort="severity">Severity</th><th data-sort="title">Title</th><th data-sort="endpoint">Endpoint</th><th data-sort="cwe">CWE</th><th data-sort="review_status">Status</th><th data-sort="wire">Wire</th><th data-sort="agent">Agent</th><th data-sort="confidence" class="col-conf">Conf.</th></tr></thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
<div class="empty-state" id="liveFindingsEmpty">No validated findings yet.</div>
|
||
</div>
|
||
<div class="run-tab-panel log-tab-panel" data-tabpanel="log" hidden>
|
||
<div class="log-panel" id="logList"></div>
|
||
<div class="send-prompt-row" id="sendPromptRow" hidden>
|
||
<span class="repl-prompt">❭</span>
|
||
<input id="sendPromptInput" type="text" autocomplete="off" spellcheck="false" placeholder="/status · /stop · /continue · or describe it in plain language" />
|
||
<button class="btn btn-sm" id="btnSendPromptTerm" title="Open this session in the full terminal">Open in terminal</button>
|
||
</div>
|
||
<div class="field-help" id="sendPromptHelp" hidden>This session stays interactive while the engagement runs — type a command or plain instruction and press Enter.</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ RUN DETAIL (past run) ============ -->
|
||
<section class="runpage" id="detailView" hidden>
|
||
<header class="run-head">
|
||
<div class="run-head-main">
|
||
<div class="run-target" id="detailTarget">—</div>
|
||
<div class="run-meta" id="detailTargetSub"></div>
|
||
<div class="run-meta"><span class="phase-dot static" id="detailDot"></span><span id="detailState">—</span></div>
|
||
<div class="run-meta run-facts" id="detailFacts"></div>
|
||
</div>
|
||
<div class="run-actions">
|
||
<a class="btn" id="detailOpenReport" target="_blank" hidden>Open report</a>
|
||
<a class="btn" id="detailOpenPdf" target="_blank" hidden>⤓ PDF</a>
|
||
<button class="btn" id="btnBuildReport" title="Regenerate this run's report from its findings">Generate report</button>
|
||
<button class="btn" id="btnGraphRecompute" title="Recompute the attack graph with the CLI (neurosploit graph)">↻ Graph</button>
|
||
<button class="btn" id="btnRetest" title="Re-run every finding's recorded proof (neurosploit poc) and see what still reproduces">⟳ Re-test</button>
|
||
<a class="btn" id="detailOpenAudit" target="_blank" hidden title="Every action this run took, hash-chained">Audit trail</a>
|
||
<button class="btn btn-danger" id="btnDeleteRun" title="Permanently delete this session and its report">🗑 Delete</button>
|
||
<button class="btn" id="btnDetailBack">← Back</button>
|
||
</div>
|
||
</header>
|
||
<nav class="run-tabs">
|
||
<button class="run-tab active" data-tab="findings">Findings <span id="detailFindingsCount">0</span></button>
|
||
</nav>
|
||
<div class="run-body">
|
||
<div class="run-tab-panel" data-tabpanel="findings">
|
||
<div class="findings-toolbar">
|
||
<div class="sev-summary" id="detailSevSummary"></div>
|
||
<div class="topbar-spacer"></div>
|
||
<div class="search-wrap">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="detailFindingSearch" type="text" placeholder="Filter findings" />
|
||
</div>
|
||
<button class="btn btn-sm" id="btnExportCsv" title="Export the filtered findings as CSV">⤓ CSV</button>
|
||
</div>
|
||
<div class="kpi-row" id="detailKpis"></div>
|
||
<div id="detailRegression" hidden></div>
|
||
<div class="table-wrap">
|
||
<table class="data-table" id="detailFindingsTable">
|
||
<thead><tr><th data-sort="severity">Severity</th><th data-sort="title">Title</th><th data-sort="endpoint">Endpoint</th><th data-sort="cwe">CWE</th><th data-sort="review_status">Status</th><th data-sort="wire">Wire</th><th data-sort="agent">Agent</th><th data-sort="confidence" class="col-conf">Conf.</th></tr></thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
<div class="empty-state" id="detailFindingsEmpty">No validated findings.</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ TERMINAL DOCK (real CLI harness session) ============ -->
|
||
<section class="term-dock" id="termDock" hidden>
|
||
<div class="term-resize" id="termResize" title="Drag to resize"></div>
|
||
<div class="term-head">
|
||
<span class="term-dot" id="termDot" data-state="off"></span>
|
||
<span class="term-title">NeuroSploit harness</span>
|
||
<select class="term-target" id="termTarget" title="Where this terminal's input goes">
|
||
<option value="session">standalone REPL session</option>
|
||
</select>
|
||
<span class="term-status" id="termStatus">disconnected</span>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="term-btn" id="btnTermClear" title="Clear screen (Ctrl+L)">clear</button>
|
||
<button class="term-btn" id="btnTermRestart" title="Start a fresh harness session">restart</button>
|
||
<button class="term-btn" id="btnTermExpand" title="Expand / collapse the dock">expand</button>
|
||
<button class="icon-btn" id="btnTermClose" title="Close (Esc)">✕</button>
|
||
</div>
|
||
<div class="term-alert" id="termAlert" hidden></div>
|
||
<div class="term-host" id="termHost"></div>
|
||
<div class="term-hints" id="termHints">
|
||
<span class="k">Enter</span> send · <span class="k">↑↓</span> history · <span class="k">Tab</span> complete · <span class="k">Ctrl+C</span> interrupt · <span class="k">Ctrl+L</span> clear
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<!-- ============ AUTH & KEYS MODAL ============ -->
|
||
<div class="modal-overlay" id="authModal" hidden>
|
||
<div class="modal">
|
||
<div class="modal-head">
|
||
<div class="title">Auth & Keys</div>
|
||
<button class="icon-btn" id="btnCloseAuth">✕</button>
|
||
</div>
|
||
<div class="modal-tabs">
|
||
<button class="modal-tab active" data-mtab="target">Target auth</button>
|
||
<button class="modal-tab" data-mtab="keys">LLM API keys</button>
|
||
<button class="modal-tab" data-mtab="creds">Creds file</button>
|
||
<button class="modal-tab" data-mtab="authz">Authorization</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="modal-panel" data-mpanel="target">
|
||
<div class="field-group">
|
||
<label class="field-label" for="authHeader">Auth header</label>
|
||
<input id="authHeader" type="text" placeholder="Authorization: Bearer <token> or Cookie: session=..." />
|
||
<div class="field-help">Used so agents test as a logged-in user. Kept only for this session, sent to the CLI as an ephemeral creds file.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Named roles (multi-identity access-control testing)</label>
|
||
<div class="role-list" id="roleList"></div>
|
||
<button class="btn btn-sm" id="btnAddRole" style="align-self:flex-start;">+ Add role</button>
|
||
<div class="field-help">Two or more roles enable IDOR/BOLA/BFLA cross-role testing.</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-panel" data-mpanel="keys" hidden>
|
||
<div class="section-title">Model provider keys</div>
|
||
<div class="field-help" style="margin:4px 0 12px;">The API keys for the <b>LLMs that run the engagement</b> (not the target's auth — that's the <em>Target auth</em> tab). Kept in this server process's memory only, never written to disk, cleared on restart.</div>
|
||
<div id="providerKeyList"></div>
|
||
</div>
|
||
<div class="modal-panel" data-mpanel="authz" hidden>
|
||
<div class="field-group">
|
||
<label class="field-label" for="capToken">Capability token</label>
|
||
<input id="capToken" type="text" placeholder="ns-cap.v1.…" spellcheck="false" />
|
||
<div class="field-status" id="capStatus"></div>
|
||
<div class="field-help">
|
||
The signed grant for this engagement: who authorized it, which hosts, which environment, until when.
|
||
It is verified by the harness (<code>NEUROSPLOIT_CAPABILITY_KEY</code>) and acts as a <strong>ceiling</strong> —
|
||
the settings below can narrow the scope, never widen it. Mint one with
|
||
<code>neurosploit capability issue</code>.
|
||
</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="inScope">Additional authorized hosts</label>
|
||
<input id="inScope" type="text" placeholder="app.example.com, *.api.example.com, 10.0.0.0/24" />
|
||
<div class="field-help">Without this the engagement is authorized against the target and nothing else — discovering a host is not permission to test it.</div>
|
||
</div>
|
||
|
||
<div class="section-title" style="margin-top:24px;margin-bottom:8px;display:flex;align-items:center;gap:8px;">
|
||
Scoping & Guardrails
|
||
<span class="pill" style="font-size:10px;">enforced in code</span>
|
||
</div>
|
||
<div class="field-help" style="margin:0 0 14px;">
|
||
The <b>hard scope</b> is the boundary: a request whose host is not listed is <b>refused before it is sent</b> — not warned about. Exclusions always win. A capability token still caps all of this. Leave the hard list empty to keep the plain target + <em>Additional authorized hosts</em> behaviour.
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeHard">Hard scope <span class="req">— the allowlist</span></label>
|
||
<textarea id="scopeHard" rows="3" placeholder="one per line, or comma-separated app.example.com *.staging.example.com https://example.com/api/v2 10.20.30.0/24"></textarea>
|
||
<div class="field-help">Exact host · <code>*.wildcard</code> (apex + subdomains) · <code>CIDR</code> · <code>https://host/path</code> prefix. Empty = nothing extra is enforced here.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeExclude">Exclusions <span class="req">— always win</span></label>
|
||
<textarea id="scopeExclude" rows="3" placeholder="payments.example.com admin.example.com https://app.example.com/billing"></textarea>
|
||
<div class="field-help">Refused even if the allowlist would cover them.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeObserve">Observe-only</label>
|
||
<textarea id="scopeObserve" rows="3" placeholder="cdn.example.com *.thirdparty.example.com"></textarea>
|
||
<div class="field-help">May be looked at (recon) but never attacked.</div>
|
||
</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label">State-changing methods</label>
|
||
<div class="check-row"><input type="checkbox" id="scopeDestructive" /> <label for="scopeDestructive">Allow DELETE / PUT / PATCH</label></div>
|
||
<div class="field-help">Off by default — a scan should not change the target's state to prove a bug.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Test accounts</label>
|
||
<div class="check-row"><input type="checkbox" id="scopeAccounts" checked /> <label for="scopeAccounts">Allow account creation</label></div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeMaxAccounts">Max accounts</label>
|
||
<input class="narrow" id="scopeMaxAccounts" type="number" min="0" value="3" />
|
||
<div class="field-help">0 = unlimited.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeRate">Requests / min</label>
|
||
<input class="narrow" id="scopeRate" type="number" min="0" value="240" />
|
||
<div class="field-help">Whole engagement. 0 = unlimited. Keep low on production.</div>
|
||
</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeForbidden">Forbidden payloads</label>
|
||
<textarea id="scopeForbidden" rows="2" placeholder="delete from drop table rm -rf /"></textarea>
|
||
<div class="field-help">Substrings NEVER acceptable, whatever the finding — the classes that damage a target instead of demonstrating a bug. Extends the built-in defaults.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="scopeNotes">Notes <span class="req">— guidance, NOT enforced</span></label>
|
||
<textarea id="scopeNotes" rows="2" placeholder="SOW-2026-0142; test window 02:00–06:00 UTC; prove PII with a canary row only"></textarea>
|
||
<div class="field-help">Context passed to the agents. Kept separate from the rules on purpose — prose is not a control.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label" for="envSelect">Environment</label>
|
||
<select id="envSelect">
|
||
<option value="production" selected>production</option>
|
||
<option value="staging">staging</option>
|
||
<option value="development">development</option>
|
||
<option value="lab">lab</option>
|
||
<option value="ot-production">ot-production (ICS/SCADA)</option>
|
||
</select>
|
||
<div class="field-help">Scales every risk score — the same action is a different act on a lab bench and on a live substation.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="policySelect">Policy profile</label>
|
||
<select id="policySelect">
|
||
<option value="web" selected>web — standard</option>
|
||
<option value="ot">ot — read-only, paced, industrial writes blocked</option>
|
||
</select>
|
||
<div class="field-help">OT blocks writes, disruptive actions, fuzzing and exploit payloads over industrial protocols, and caps the rate at ~1 req/s.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-title" style="margin-top:18px;">Egress & out-of-band</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="transportSpec">Transport (how traffic reaches the target)</label>
|
||
<input id="transportSpec" type="text" placeholder="direct · socks5://127.0.0.1:1080 · openvpn:/path/client.ovpn · ssh://red@bastion.corp?forward=10.0.0.5:445 · cloudflared://db.internal:5432" spellcheck="false" />
|
||
<div class="field-help">
|
||
An <strong>internal</strong> target with no transport is <strong>refused</strong>, not tested — with the VPN down,
|
||
<code>10.20.0.15</code> belongs to whatever network this host is on, which is not the client's.
|
||
</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label" for="oobDomain">Out-of-band domain</label>
|
||
<input id="oobDomain" type="text" placeholder="oob.yourdomain.com" spellcheck="false" />
|
||
<div class="field-help">A wildcard pointed at this host. Without it blind SSRF/XXE/RCE can only be reported as leads — never confirmed.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="oobHttp">OOB HTTP listener</label>
|
||
<input id="oobHttp" type="text" placeholder="0.0.0.0:8080" spellcheck="false" />
|
||
<div class="field-help">Where callbacks land. An HTTP callback proves egress; a DNS query alone does not.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="oobDns">OOB DNS listener</label>
|
||
<input id="oobDns" type="text" placeholder="0.0.0.0:5353" spellcheck="false" />
|
||
<div class="field-help">Only if the zone is delegated here (NS record).</div>
|
||
</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="smsSpec">Inbound SMS (OTP & rate-limit work)</label>
|
||
<input id="smsSpec" type="text" placeholder="twilio:<sid>:<token>:+15550101 · webhook:https://…/inbox:+15550101" spellcheck="false" />
|
||
<div class="field-help">A throttling claim counts <strong>delivered messages carrying distinct codes</strong>, not HTTP 200s.</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-panel" data-mpanel="creds" hidden>
|
||
<div class="field-group">
|
||
<label class="field-label" for="credsPath">creds.yaml path (overrides target auth above)</label>
|
||
<input id="credsPath" type="text" placeholder="creds.yaml" />
|
||
<div class="field-help">An explicit file on disk — see neurosploit-rs/creds.example.yaml for the schema (jwt/header/cookie/login/roles/ssh/windows/cloud).</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="collectionFile">API collection (Postman / OpenAPI / Swagger / HAR)</label>
|
||
<input id="collectionFile" type="file" accept=".json,application/json,.har" multiple />
|
||
<input id="collectionPath" type="text" placeholder="…or a path on disk: file.json or a directory of .json files" />
|
||
<div class="field-help" id="collectionHelp">Imports endpoints as known surface — file or directory of .json files. Every route is tested directly, alongside recon.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ CUSTOM LEAD MODAL ============ -->
|
||
<div class="modal-overlay" id="leadModal" hidden>
|
||
<div class="modal modal-sm">
|
||
<div class="modal-head">
|
||
<div class="title">Custom lead</div>
|
||
<button class="icon-btn" id="btnCloseLead">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="field-help" style="margin-bottom:14px;">A <b>lead</b> is a specialist agent the harness runs. Add one two ways — let Claude write it from a description, or paste your own agent / system prompt to run verbatim. Either way it is saved as a real, pinnable agent in <code>agents_md/vulns/</code> and you can remove it later.</div>
|
||
<div class="seg-tabs" id="leadModeTabs">
|
||
<button class="seg-tab active" data-leadmode="describe">Describe it</button>
|
||
<button class="seg-tab" data-leadmode="own">Paste my own</button>
|
||
</div>
|
||
<div class="field-group" data-leadpanel="describe">
|
||
<label class="field-label" for="leadDesc">What should this lead test?</label>
|
||
<textarea id="leadDesc" placeholder="e.g. Abuse the invoice PDF export to read internal files via the template engine."></textarea>
|
||
<div class="field-help">Claude (Opus, subscription) writes a real specialist agent for it and pins it. If generation is unavailable, the text is folded into <code>--focus</code> instead.</div>
|
||
</div>
|
||
<div class="field-group" data-leadpanel="own" hidden>
|
||
<label class="field-label" for="leadName">Name</label>
|
||
<input id="leadName" type="text" placeholder="e.g. GraphQL Introspection Abuse" />
|
||
<label class="field-label" for="leadOwn" style="margin-top:10px;">Your agent / system prompt</label>
|
||
<textarea id="leadOwn" rows="10" placeholder="Paste a full agent markdown (# Title / ## User Prompt / ## System Prompt), or just your system prompt — it will be wrapped into an agent. Use {target} and {recon_json} placeholders."></textarea>
|
||
<div class="field-help">Used verbatim — no model rewrites it. {target} and {recon_json} are filled per run.</div>
|
||
</div>
|
||
<div class="field-error" id="errLead" hidden></div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="btn" id="btnLeadCancel">Cancel</button>
|
||
<button class="btn btn-primary" id="btnLeadGenerate">Add lead</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ FINDING DETAIL MODAL ============ -->
|
||
<div class="modal-overlay" id="findingModal" hidden>
|
||
<div class="modal modal-lg">
|
||
<div class="modal-head">
|
||
<div>
|
||
<span class="sev" id="fmSev">—</span>
|
||
<span class="title" id="fmTitle" style="margin-left:8px;">—</span>
|
||
</div>
|
||
<button class="icon-btn" id="btnCloseFinding">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="review-grid" id="fmMeta" style="margin-bottom: var(--sp-5);"></div>
|
||
|
||
<div id="fmSection-evidence"></div>
|
||
<div id="fmSection-impact"></div>
|
||
<div id="fmSection-remediation"></div>
|
||
<div id="fmSection-chains"></div>
|
||
|
||
<div class="field-group" id="fmSection-wire">
|
||
<div class="fm-wire-head">
|
||
<label class="field-label">Wire evidence — the bytes behind this finding</label>
|
||
<button class="btn btn-sm" id="btnFindingRetest">⟳ Re-test this finding</button>
|
||
</div>
|
||
<div id="fmWireSummary"></div>
|
||
<div id="fmRetestHistory"></div>
|
||
<div id="fmWireExchanges" class="wire-exchanges"></div>
|
||
</div>
|
||
|
||
<div class="field-group">
|
||
<label class="field-label">Other scripts from this run</label>
|
||
<div id="fmPocList" class="field-help">—</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ ADD REPOSITORY MODAL ============ -->
|
||
<div class="modal-overlay" id="repoModal" hidden>
|
||
<div class="modal modal-sm">
|
||
<div class="modal-head">
|
||
<div class="title">Add Repository</div>
|
||
<button class="icon-btn" onclick="$('#repoModal').hidden=true">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="field-group">
|
||
<label class="field-label" for="repoUrl">Repository URL or path</label>
|
||
<input id="repoUrl" type="text" placeholder="https://github.com/owner/repo or /path/to/repo" spellcheck="false" />
|
||
<div class="field-help">GitHub URL, owner/repo shorthand, GitLab URL, or a local path.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="repoName">Display name (optional)</label>
|
||
<input id="repoName" type="text" placeholder="My API" />
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="repoBranch">Default branch</label>
|
||
<input id="repoBranch" type="text" placeholder="main" value="main" />
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="repoDesc">Description (optional)</label>
|
||
<input id="repoDesc" type="text" placeholder="Production API service" />
|
||
</div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="btn" onclick="$('#repoModal').hidden=true">Cancel</button>
|
||
<button class="btn btn-primary" id="btnRepoSubmit">Add Repository</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ ADD DOMAIN MODAL ============ -->
|
||
<div class="modal-overlay" id="domainModal" hidden>
|
||
<div class="modal modal-sm">
|
||
<div class="modal-head">
|
||
<div class="title">Add Domain</div>
|
||
<button class="icon-btn" onclick="$('#domainModal').hidden=true">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="field-group">
|
||
<label class="field-label" for="domainName">Domain</label>
|
||
<input id="domainName" type="text" placeholder="app.example.com" spellcheck="false" />
|
||
<div class="field-help">The target domain for black-box scanning. Subdomains will be discovered during recon.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="domainType">Type</label>
|
||
<select id="domainType">
|
||
<option value="web" selected>Web application</option>
|
||
<option value="api">API</option>
|
||
<option value="llm">LLM endpoint</option>
|
||
<option value="mobile">Mobile backend</option>
|
||
<option value="other">Other</option>
|
||
</select>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="domainDesc">Description (optional)</label>
|
||
<input id="domainDesc" type="text" placeholder="Production web application" />
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="domainScope">Scope</label>
|
||
<select id="domainScope">
|
||
<option value="in-scope" selected>In scope</option>
|
||
<option value="observe-only">Observe only</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="btn" onclick="$('#domainModal').hidden=true">Cancel</button>
|
||
<button class="btn btn-primary" id="btnDomainSubmit">Add Domain</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ ADD NETWORK MODAL ============ -->
|
||
<div class="modal-overlay" id="networkModal" hidden>
|
||
<div class="modal modal-sm">
|
||
<div class="modal-head">
|
||
<div class="title">Add Network</div>
|
||
<button class="icon-btn" onclick="$('#networkModal').hidden=true">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="field-group">
|
||
<label class="field-label" for="networkCidr">CIDR or host</label>
|
||
<input id="networkCidr" type="text" placeholder="10.0.0.0/24 or 192.168.1.10" spellcheck="false" />
|
||
<div class="field-help">Network range in CIDR notation, or a single IP/hostname.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="networkName">Name (optional)</label>
|
||
<input id="networkName" type="text" placeholder="Corporate LAN" />
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="networkDesc">Description (optional)</label>
|
||
<input id="networkDesc" type="text" placeholder="Internal network segment" />
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="networkTransport">Transport</label>
|
||
<input id="networkTransport" type="text" placeholder="direct / socks5://host:port / ssh://user@bastion" spellcheck="false" />
|
||
<div class="field-help">How to reach this network. Leave empty for direct access.</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="btn" onclick="$('#networkModal').hidden=true">Cancel</button>
|
||
<button class="btn btn-primary" id="btnNetworkSubmit">Add Network</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ INTEGRATION CONFIG MODAL ============ -->
|
||
<div class="modal-overlay" id="integrationModal" hidden>
|
||
<div class="modal modal-sm">
|
||
<div class="modal-head">
|
||
<div class="title" id="integModalTitle">Configure Integration</div>
|
||
<button class="icon-btn" onclick="$('#integrationModal').hidden=true">✕</button>
|
||
</div>
|
||
<div class="modal-body" id="integModalBody">
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="btn" onclick="$('#integrationModal').hidden=true">Cancel</button>
|
||
<button class="btn btn-primary" id="btnIntegSubmit">Save</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toasts" id="toasts"></div>
|
||
|
||
<script src="/vendor/xterm.js"></script>
|
||
<script src="/vendor/xterm-addon-fit.js"></script>
|
||
<script src="/app.js"></script>
|
||
</body>
|
||
</html>
|