feat: security hardening across WMP client library - #19
Merged
Merged
Conversation
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.
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.
- 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
force-pushed
the
feat/security-hardening-2026-07-21
branch
from
July 21, 2026 14:36
c3a66d1 to
952d08d
Compare
…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.
|
There was a problem hiding this comment.
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 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 on lines
145
to
149
| @@ -87,7 +149,7 @@ export function decodeBatch(data: string): Message[] { | |||
| return item as Message; | |||
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))); | ||
| } | ||
| } |
| oid4vci?: OID4VCICapability; | ||
|
|
||
| /** OID4VP capability. Omit to disable presentation. */ | ||
| /** OID4VCI capability. Omit to disable issuance. */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Addresses 14 security findings from an internal security review of
@sirosfoundation/wmp-js.Changes
Cryptographic & identity hardening
src/jsonrpc.ts): replaced predictable sequential counter (req-1,req-2, …) with CSPRNG-based IDs.src/invitation.ts): addedverifyInvitation()helper; parsing functions now explicitly do not verify and callers must validate.src/mls.ts): requiresexplicitlyInsecure: trueto reduce risk of accidental plaintext transmission.src/peer.ts):createSessionnow validates that the response contains asession_idand an acceptable WMP version.Input validation & DoS resistance
src/jsonrpc.ts): added configurablemaxSizeandmaxDepthtodecodeMessage/decodeBatch.src/native.ts):StdioTransportandUnixSocketTransportnow enforce a configurablemaxLineLengthand close on overflow.src/schema.ts): optional strict mode returns errors for unknown methods/responses instead of silently accepting them.did:webdomain validation (src/discovery.ts): rejects malformed or oversized extracted hostnames.Authorization & access control
src/peer.ts): optionalvalidatorruns before dispatching incoming requests.src/peer.ts): optionalauthorizecallback can reject requests/notifications.src/openid4x.ts):OpenID4xProfilenow handleswmp.credential.notification, requiring thenotification_idto be registered for an outstanding issuance flow.Transport & information disclosure
src/transport.ts): validates scheme; blocks unencryptedws://unlessallowInsecure: true.src/transport.ts): addedreconnectSSE()for re-establishing the SSE stream after token/session changes.src/peer.ts): unexpected handler errors are logged locally and returned as genericInternalErrorto avoid leaking implementation details.Exports
UnixSocketTransportOptionsexported from@sirosfoundation/wmp-js/node(src/node.ts).Test coverage
test/security.test.ts(29 tests) covering all new security behavior.test/jsonrpc.test.tsto reflect random request IDs.Checklist
npm run buildpassesnpm testpassesnpm auditreports zero vulnerabilities