mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-29 12:31:43 +02:00
New `mobile` engagement mode: `neurosploit mobile <app.apk|app.ipa|binary>` reverse-engineers a local artifact with a dedicated `mobile` agent set, all headless and provisioned on demand (Ghidra analyzeHeadless, MobSF REST/Docker, Frida, apktool/jadx, radare2). Twelve original, generic skills (agents_md/mobile/, English): static binary triage, APK static analysis, IPA static analysis, RASP & anti-tamper mapping, root/jailbreak detection + bypass, TLS pinning detection + bypass, anti-debug detection + bypass, obfuscation analysis & deobfuscation, code-integrity / tamper-check bypass, hardcoded-secrets extraction, insecure local storage, and mobile network traffic analysis. Findings are proven from the artifact (decompilation or Frida trace), non-destructively. - agents.rs: new `mobile` Library category (loaded, counted). - pipeline.rs: run_mobile() mirroring the host pipeline with a mobile recon and headless tooling doctrine; exported from the crate. - CLI: `Cmd::Mobile` + `Mode::Mobile`, wired in main and the TUI. - README + TUTORIAL document the new test type; engagement-modes badge + table updated; "New in v4.2.0" note. Version bumped to 4.2.0 across the workspace. 383 tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
663 lines
38 KiB
HTML
663 lines
38 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.2.0 — Console</title>
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🧠</text></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"><span class="mark">NS</span> NeuroSploit</div>
|
||
<button class="icon-btn" id="btnThemeToggle" title="Toggle light / dark theme">☾</button>
|
||
</div>
|
||
|
||
<button class="sb-new" id="btnNewEngagement">+ New engagement</button>
|
||
<button class="sb-link" id="btnDashboard">▤ Dashboard</button>
|
||
|
||
<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 class="sb-bottom">
|
||
<span class="sb-version" id="sbVersion">v4.2.0</span>
|
||
<div class="sb-bottom-actions">
|
||
<button class="icon-btn" id="btnOpenAuth" title="Auth & API keys">🔑</button>
|
||
<button class="icon-btn" id="btnOpenRepl" title="Open terminal (Ctrl+`)">❭_</button>
|
||
</div>
|
||
</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>
|
||
|
||
<!-- ============ WIZARD (new engagement) ============ -->
|
||
<section class="wizard" id="wizardView">
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">New engagement</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>
|
||
</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>
|
||
|
||
<!-- 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="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">
|
||
<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="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">own 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">own + Burp</option>
|
||
<option value="own+caido">own + 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="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">← New engagement</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>
|
||
<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="attackpath">Generative Attack Path Chaining</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="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" data-tabpanel="attackpath" hidden><div id="liveAttackPath"></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>
|
||
<a class="btn" id="detailOpenAudit" target="_blank" hidden title="Every action this run took, hash-chained">Audit trail</a>
|
||
<button class="btn" id="btnDetailBack">← New engagement</button>
|
||
</div>
|
||
</header>
|
||
<nav class="run-tabs">
|
||
<button class="run-tab active" data-tab="findings">Findings <span id="detailFindingsCount">0</span></button>
|
||
<button class="run-tab" data-tab="attackpath">Generative Attack Path Chaining</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>
|
||
</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="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 class="run-tab-panel" data-tabpanel="attackpath" hidden><div id="detailAttackPath"></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">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="field-help" style="margin-bottom:12px;">Keys are 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:20px;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:-6px 0 10px;">
|
||
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>
|
||
</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-group">
|
||
<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) generates a real specialist agent file for it and pins it. If generation is unavailable, the text is folded into <code>--focus</code> instead.</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">Generate 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">
|
||
<label class="field-label">Other scripts from this run</label>
|
||
<div id="fmPocList" class="field-help">—</div>
|
||
</div>
|
||
</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>
|