Skip to content

feat: security hardening across WMP client library - #19

Merged
leifj merged 8 commits into
mainfrom
feat/security-hardening-2026-07-21
Jul 22, 2026
Merged

leifj merged 8 commits into
mainfrom
feat/security-hardening-2026-07-21

Conversation

@leifj

@leifj leifj commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses 14 security findings from an internal security review of @sirosfoundation/wmp-js.

Changes

Cryptographic & identity hardening

  • Random JSON-RPC request IDs (src/jsonrpc.ts): replaced predictable sequential counter (req-1, req-2, …) with CSPRNG-based IDs.
  • Invitation signature verification (src/invitation.ts): added verifyInvitation() helper; parsing functions now explicitly do not verify and callers must validate.
  • NoopMLSProvider misuse prevention (src/mls.ts): requires explicitlyInsecure: true to reduce risk of accidental plaintext transmission.
  • Session binding verification (src/peer.ts): createSession now validates that the response contains a session_id and an acceptable WMP version.

Input validation & DoS resistance

  • Bounded JSON parsing (src/jsonrpc.ts): added configurable maxSize and maxDepth to decodeMessage / decodeBatch.
  • Native transport line limits (src/native.ts): StdioTransport and UnixSocketTransport now enforce a configurable maxLineLength and close on overflow.
  • Schema validator strict mode (src/schema.ts): optional strict mode returns errors for unknown methods/responses instead of silently accepting them.
  • did:web domain validation (src/discovery.ts): rejects malformed or oversized extracted hostnames.

Authorization & access control

  • Peer validator hook (src/peer.ts): optional validator runs before dispatching incoming requests.
  • Peer authorization hook (src/peer.ts): optional authorize callback can reject requests/notifications.
  • OID4VCI notification validation (src/openid4x.ts): OpenID4xProfile now handles wmp.credential.notification, requiring the notification_id to be registered for an outstanding issuance flow.

Transport & information disclosure

  • WebSocket URL validation (src/transport.ts): validates scheme; blocks unencrypted ws:// unless allowInsecure: true.
  • SSE reconnect (src/transport.ts): added reconnectSSE() for re-establishing the SSE stream after token/session changes.
  • Error sanitization (src/peer.ts): unexpected handler errors are logged locally and returned as generic InternalError to avoid leaking implementation details.

Exports

  • UnixSocketTransportOptions exported from @sirosfoundation/wmp-js/node (src/node.ts).

Test coverage

  • Added comprehensive test/security.test.ts (29 tests) covering all new security behavior.
  • Updated test/jsonrpc.test.ts to reflect random request IDs.
  • Full suite: 201 tests passing.

Checklist

  • npm run build passes
  • npm test passes
  • npm audit reports zero vulnerabilities

leifj added 2 commits July 17, 2026 23:12
Per wmp-erds-alignment.prompt.md and WMP spec §3.2–3.8, §7.5.1:

Types:
- SenderDelegate, DelegateAuthorization in Metadata
- deliver_after field in Metadata
- MessageDeliverParams: reply_to, in_reply_to, message_type,
  consignment_mode, recipient_assurance_level, applicable_policies
- ConsignmentMode and AssuranceLevel type unions

Error codes:
- DelegationInvalid (-31015)
- ConsignmentModeUnsupported (-31016)
- AssuranceLevelUnsupported (-31017)
- PolicyUnsupported (-31018)

Well-known config:
- ErdsMetadata and RecipientMetadata interfaces

Evidence (new module):
- Evidence interface with all ETSI EN 319 522 fields
- EvidenceEventReason interface and reason code constants
- All new event type constants (handover, notification, gateway)
- Exported from index.ts
Address 14 security findings from internal review:

- Randomise JSON-RPC request IDs using crypto.getRandomValues
- Bound JSON-RPC parsing: configurable maxSize and maxDepth
- Add optional Peer validator and authorize hooks
- Sanitise unexpected handler errors in RPC responses
- Validate session.create responses (session_id, version)
- Add strict mode to schema validator (errors for unknown methods)
- Validate WebSocket URL schemes; block ws:// unless allowInsecure
- Add SSE reconnect method after authorization/session changes
- Require explicitlyInsecure: true for NoopMLSProvider
- Add verifyInvitation for detached JWS signature verification
- Validate did:web domain extraction
- Bound native transport (stdio/Unix socket) line buffers
- Validate OID4VCI credential notifications against registered IDs
- Export UnixSocketTransportOptions from node entry

Tests: add comprehensive security.test.ts; update jsonrpc.test.ts for random IDs.
Comment thread test/security.test.ts Fixed
Comment thread test/security.test.ts Fixed
Comment thread test/security.test.ts Fixed
Comment thread test/security.test.ts Fixed
Comment thread test/security.test.ts Fixed
Runs the vectors in wmp/vectors/interop.json against wmp-js to verify
cross-implementation behavior for resolve, method-not-found, notifications,
authorization, validation, and handler errors.
Comment thread test/interop.test.ts Fixed
leifj added 3 commits July 21, 2026 15:38
- test/interop: search both local sibling path and CI checkout path for vectors/interop.json
- test/security: remove unused HttpSseTransport, UnixSocketTransport, parseInvitationURI, OID4FlowType imports
Move the identical MockTransport class from test/interop.test.ts and
test/security.test.ts into test/mock-transport.ts so SonarCloud's new-code
duplication threshold is no longer exceeded.
@leifj
leifj force-pushed the feat/security-hardening-2026-07-21 branch from c3a66d1 to 952d08d Compare July 21, 2026 14:36
leifj added 2 commits July 21, 2026 18:51
…ering

- src/jsonrpc.ts: extract parseJSONRPC helper shared by decodeMessage/decodeBatch
- src/native.ts: introduce LineBuffer helper used by StdioTransport and
  UnixSocketTransport, eliminating duplicated onData logic
The createSession convenience method now passes invitation_nonce through
to the SessionCreateParams, allowing callers to correlate sessions with
the invitation that initiated them.
Copilot AI review requested due to automatic review settings July 22, 2026 13:04
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a broad set of security-hardening measures across the WMP JS client library, tightening cryptographic handling, transport safety, input validation, and request authorization/validation hooks.

Changes:

  • Harden JSON-RPC and transport handling (randomized request IDs, bounded decoding, WebSocket URL validation, SSE reconnect, native line-length limits).
  • Add peer-side validation/authorization hooks and sanitize unexpected handler errors to avoid leaking internals.
  • Extend protocol/types support (delegation/consignment/assurance metadata, evidence types) and add/expand security + interop test coverage.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/security.test.ts Adds a comprehensive security regression suite covering new hardening behaviors.
test/mock-transport.ts Introduces an in-memory transport for deterministic peer/transport tests.
test/jsonrpc.test.ts Updates JSON-RPC tests for random request IDs.
test/interop.test.ts Adds shared-vector interoperability tests for cross-implementation compatibility.
src/types.ts Extends core types and error codes (delegation/consignment/assurance).
src/transport.ts Adds WebSocket URL scheme enforcement, SSE reconnect, and bounded message decoding.
src/schema.ts Adds optional strict mode for unknown method/response schema validation.
src/peer.ts Adds validator/authorize hooks, session binding checks, and error sanitization.
src/openid4x.ts Adds credential notification method handling with notification_id validation.
src/node.ts Exports UnixSocketTransportOptions from the Node entrypoint.
src/native.ts Adds line-length limiting via LineBuffer for stdio/unix transports.
src/mls.ts Requires explicit opt-in for NoopMLSProvider to prevent accidental insecure use.
src/jsonrpc.ts Implements random request IDs and bounded JSON parsing for decodeMessage/decodeBatch.
src/invitation.ts Adds verifyInvitation helper and clarifies parsing vs verification responsibilities.
src/index.ts Exports new types/constants and evidence-related exports.
src/evidence.ts Adds evidence event/reason/type definitions for ERDS alignment.
src/discovery.ts Hardens did:web domain extraction/validation and expands well-known metadata types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/jsonrpc.ts
Comment on lines +89 to +107
function parseJSONRPC(data: string, maxSize: number, maxDepth: number): unknown {
if (data.length > maxSize) {
throw new Error("JSON-RPC message exceeds maximum size");
}

try {
return JSON.parse(data, (_key, value) => {
if (value !== null && typeof value === "object") {
checkDepth(value, 1, maxDepth);
}
return value;
});
} catch (err) {
if (err instanceof Error && err.message.includes("depth")) {
throw err;
}
throw new Error("Invalid JSON-RPC payload");
}
}
Comment thread src/jsonrpc.ts
Comment on lines 145 to 149
@@ -87,7 +149,7 @@ export function decodeBatch(data: string): Message[] {
return item as Message;
Comment thread src/native.ts
Comment on lines +58 to +79
this.buffer += chunk;

if (this.buffer.length > this.maxLineLength) {
this.onError(new Error("Native transport line exceeds maximum length"));
this.close();
return;
}

const lines = this.buffer.split("\n");
// Last element is incomplete (may be empty string if chunk ended with \n)
this.buffer = lines.pop()!;

for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
try {
const msg = decodeMessage(trimmed);
this.onMessage(msg);
} catch (err) {
this.onError(err instanceof Error ? err : new Error(String(err)));
}
}
Comment thread src/openid4x.ts
oid4vci?: OID4VCICapability;

/** OID4VP capability. Omit to disable presentation. */
/** OID4VCI capability. Omit to disable issuance. */
@leifj
leifj merged commit a371828 into main Jul 22, 2026
13 checks passed
@leifj
leifj deleted the feat/security-hardening-2026-07-21 branch July 22, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants