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

req HttpRequestMessage
headers IList<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

scope IList<string>
targetUrl string

Returns

Func<string, bool>

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

options ScanOptions
ct CancellationToken
output TextWriter
error TextWriter

Returns

Task<int>