Bounded WebSocket review
Status: Preview, development-only, explicit opt-in. The anonymous S11-A path remains the default. S11-B adds one explicit health-qualified V1 Authorization-header supplied-session composition without changing that default.
Selection and authority
The capability is compiled only with the non-default websocket-review
feature and is selected only by:
termivar scan AUTHORIZED_TARGET \
--profile web-review \
--websocket-review-policy FILE \
--report-dir NEW_DIRECTORY
The strict security.websocket-review-policy/v1 file declares one exact
endpoint, a finite ordered message exchange and finite limits. It must state
target_authorized=true, messages_read_only_acknowledged=true and
message_content_is_non_secret=true. Those are operator assertions, not facts
Termivar authenticates. V1 does not support credentials or other secret material
inside message bodies. A GET, Upgrade or application message is not guaranteed
to be side-effect-free by protocol alone.
The endpoint must retain the target's exact host and effective port and remain
inside the selected application path using segment-aware matching. The policy
cannot discover another endpoint or expand target scope. Plain ws is admitted
only when both the target and endpoint use numeric loopback. Other execution
requires wss and ordinary certificate validation. Userinfo, fragments, query
strings, unsafe raw encodings and path traversal are rejected before dispatch.
When both websocket-review and supplied-session-review are compiled, the
same assessment may explicitly select the narrow session composition:
termivar scan AUTHORIZED_TARGET \
--profile web-review \
--websocket-review-policy WEBSOCKET_POLICY \
--websocket-supplied-session \
--session-policy SESSION_POLICY \
--session-auth-file AUTHORIZATION_SECRET \
--report-dir NEW_DIRECTORY
This composition accepts only security.supplied-session-policy/v1 with the
authorization_header mechanism and exactly one protected resource. Cookie V2
and bounded-form-login V3 policies are rejected after non-secret policy
validation but before output reservation or secret acquisition. The WebSocket
and WordPress supplied-session consumers cannot be selected together. Without
--websocket-supplied-session, selecting both policies still runs the original
standalone supplied-session review and anonymous WebSocket review.
The combined sequence is startup health, one protected resource staged but not yet committed, one credentialed WebSocket handshake/exchange, then terminal health. Startup loss prevents the WebSocket request. Only healthy startup and terminal checkpoints qualify the declared application, operator-declared principal and fixed epoch; terminal loss retains bounded value-free wire facts but leaves the WebSocket context unqualified and the resource uncommitted. Health checkpoints do not prove continuous authentication or identity.
The runtime mints one one-shot child from the existing assessment authority. One connection attempt consumes one request-accounting lease and shares the parent deadline, cancellation and response-byte ceiling. There is no second scanner, background worker or resettable budget. The exchange is passive-stage protocol observation; it does not mint active-verification or finding authority.
Transport contract
V1 implements RFC 6455 over an HTTP/1.1 Upgrade. HTTP/2 extended CONNECT is unsupported. It uses one isolated connection. The default path sends no Cookie, Authorization or Proxy-Authorization header. The combined S11-B path sends only the selected V1 Authorization value to the exact admitted WebSocket endpoint; it never sends Cookie or Proxy-Authorization and never imports another ambient credential. Ambient proxies, redirect following, retries, reconnection and per-message connection resets are absent. Compression is disabled and an unexpected negotiated extension is refused.
An optional subprotocol is an exact bounded token. The server must select that
exact token when one was requested, and must not invent one when none was
requested. Origin may either be omitted or derived from the authorized
application origin. Because a non-browser client can choose Origin, server
behavior observed with that header is not evidence of a browser exploit path
or cross-site WebSocket hijacking.
The compiled ceilings are:
- one connection at a time and one connection attempt;
- one to eight sequential operator-declared text messages;
- at most 64 KiB aggregate application payload in each direction;
- bounded per-message sizes no greater than the aggregate ceiling;
- at most sixteen observable Ping/Pong/Close control-frame events, narrowed by the policy;
- at most ten seconds or the smaller remaining parent deadline.
Binary application messages and unexpected message sequences fail closed. Ping/Pong/Close events are handled only within the bounded exchange; there is no keepalive or reconnection loop. The WebSocket backend yields complete application messages and observable control events, but not a trustworthy count of physical continuation frames. The audit therefore marks physical frame count unavailable instead of inventing one. Per-frame/per-message size configuration, control-event limits, cumulative application-byte limits and the absolute deadline bound processing despite that limitation.
Byte and completeness accounting
Two scopes remain distinct:
- raw socket transport bytes are counted at the owned stream boundary so a
handshake failure, partial frame or timeout is not reported as zero work;
for
wssthis scope is TLS ciphertext and includes transport framing; - application bytes are counted only for complete delivered text messages and are used for expected-response length and digest comparison.
Raw transport bytes must not be described as decoded application payload, and complete-message accounting must not hide a partial transport failure. The parent response budget charges raw inbound socket bytes. Outbound application bytes are a child-local counter because the HTTP request-body budget has a different semantic meaning. Configured bytes are not counted as sent until the send operation succeeds.
Completeness is configured_exchange_complete only when the one Upgrade and
every declared send/response pair complete inside all limits. Cancellation,
deadline, authority refusal, handshake failure, mismatched protocol negotiation,
partial/oversized input, response-budget exhaustion or another transport error
leaves the review incomplete with a bounded value-free failure class.
Evidence and claims
The anonymous report section uses security.websocket-review-audit/v1; the
selected S11-B context uses security.websocket-review-audit/v2. Both retain
capability identity termivar.websocket-review/v1 and only opaque policy,
application, endpoint, message and expected/observed response references;
lengths; bounded counters; classified outcomes; limits; and completeness. It
does not retain endpoint paths or queries, message IDs/text, subprotocol values,
credentials, raw server errors or transcripts.
Each message id is a non-secret operator revision handle and must change when
the corresponding outbound or expected-response semantics change. Public
message and expected-response references derive only from that handle and public
lengths; they do not hash either private byte sequence and therefore do not
publish a low-entropy dictionary oracle. The exact expected-response SHA-256
remains private inside the selected runtime.
An expected response is compared using its complete byte length and SHA-256. A match proves only that the complete next application message equalled the operator-declared bytes in that run. A successful Upgrade or match does not establish:
- browser-origin security;
- authentication or authorization;
- availability;
- source authenticity;
- a vulnerability, exploitability or impact.
The v2 context additionally retains opaque supplied-session policy,
application, principal and epoch references, operator-declared assurance,
credential-mechanism class, startup/terminal health outcomes and the exact
context_qualified or context_unqualified state. It never retains the
Authorization value or a credential-derived public digest. Authentication and
authorization claim limits remain not established, including after a matched
exchange.
The capability adds no assessment item or severity. Report Verify checks saved bundle integrity and schema consistency, not endpoint truth. Report Compare separates methodology, coverage and outcome changes; a missing/incomplete later exchange is not a vulnerability fix or resource removal. Offline Verify and Compare never reconnect.
Packaging and acceptance
websocket-review is outside default, the seven-member release-bundle, the
published alpha.2 archives and the initial curated package. Stock package
capabilities must list it as not_compiled. Feature-specific CI builds and
executes the actual CLI against an owned numeric-loopback fixture on Linux,
Windows, Intel macOS and Apple Silicon. That fixture is development evidence,
not authorization to contact a public endpoint or a claim of general protocol
compatibility.
Primary protocol references are RFC 6455 and RFC 8441. They are development references and are never scan-time destinations.