Class ScanCommand
- Namespace
- Kuestenlogik.Bowire.Security.Scanner
- Assembly
- Kuestenlogik.Bowire.Security.Scanner.dll
Implementation of bowire scan — the Tier-1 anchor of the
security-testing lane (docs/architecture/security-testing.md).
Loads vulnerability templates (recordings flagged
Attack), replays each one's probe
against a target URL, evaluates AttackPredicate against
the response, and emits findings.
public static class ScanCommand
- Inheritance
-
ScanCommand
- Inherited Members
Remarks
v1 scope: HTTP-class probes only (rest, graphql,
odata, http, sse, signalr, socketio,
mcp). These are HTTP-class because the request the template
probes is a plain HTTP call: SignalR's negotiate, Socket.IO's
Engine.IO polling handshake, and MCP's Streamable-HTTP JSON-RPC POST.
WebSocket / MQTT / raw-gRPC probes still surface as
Kuestenlogik.Bowire.Security.Scanner.ScanFindingStatus.Skipped with a "transport not yet
supported by scanner" message — the templates still load, they just
don't run yet. Later iterations route non-HTTP probes through the
corresponding protocol plugin's invoke path.
Methods
ApplyAuthHeaders(HttpRequestMessage, IList<string>)
Apply the operator-supplied auth headers to a probe request.
Each entry is a Name: Value string; the first colon is
the separator (so a value with embedded colons like a Bearer
token containing dots works). Names that fail validation
(e.g. with spaces) are silently dropped — the scanner is best-
effort here; the operator can debug with --verbose if a header
is misformed.
public static void ApplyAuthHeaders(HttpRequestMessage req, IList<string> headers)
Parameters
reqHttpRequestMessageheadersIList<string>
CompileScope(IList<string>, string)
Compile the scope-glob list into a single host-membership
predicate. Patterns: plain hostname (literal match), or a
leading *. wildcard (matches any sub-domain but not
the apex). Empty scope list ⇒ derive from the target's own
host so accidental cross-host probes are blocked by default.
public static Func<string, bool> CompileScope(IList<string> scope, string targetUrl)
Parameters
Returns
RunAsync(ScanOptions, CancellationToken, TextWriter?, TextWriter?)
One scan-subcommand invocation. Returns the process exit code: 0 = the scanner ran end-to-end (with or without findings; findings are the product, not a failure), 1 = reserved for unhandled tool crashes / unexpected scanner aborts, 2 = usage / configuration error before the scan starts.
<p>
<code class="paramref">output</code> and <code class="paramref">error</code> let the
caller redirect stdout / stderr without touching process-global
<xref href="System.Console.Out" data-throw-if-not-resolved="false"></xref>. Defaults wire to the real console for
the production CLI path; the System.CommandLine handler hands
the framework's <code>ParseResult.InvocationConfiguration.Output/.Error</code>
through, and tests pass their own <xref href="System.IO.StringWriter" data-throw-if-not-resolved="false"></xref> to
capture the run without serialising on a global lock.
</p>
public static Task<int> RunAsync(ScanOptions options, CancellationToken ct, TextWriter? output = null, TextWriter? error = null)
Parameters
optionsScanOptionsctCancellationTokenoutputTextWritererrorTextWriter