From df0189c909eb7c377c05ad17e52d703960ff8a12 Mon Sep 17 00:00:00 2001 From: Vladislav Svolsky <13217806+633kh4ck@users.noreply.github.com> Date: Wed, 31 Jan 2024 17:07:47 +0300 Subject: [PATCH] chore: prevent abuse with prototype pollution --- packages/core/src/controllers/pairing.ts | 4 ++-- .../sign-client/src/controllers/engine.ts | 24 ++++++++++++------- packages/utils/src/namespaces.ts | 10 ++++---- packages/utils/src/uri.ts | 2 +- packages/web3wallet/src/controllers/engine.ts | 4 ++-- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/packages/core/src/controllers/pairing.ts b/packages/core/src/controllers/pairing.ts index 05d789a5f..20cb85dff 100644 --- a/packages/core/src/controllers/pairing.ts +++ b/packages/core/src/controllers/pairing.ts @@ -154,7 +154,7 @@ export class Pairing implements IPairing { await this.isValidPing(params); const { topic } = params; if (this.pairings.keys.includes(topic)) { - const id = await this.sendRequest(topic, "wc_pairingPing", {}); + const id = await this.sendRequest(topic, "wc_pairingPing", Object.create(null)); const { done, resolve, reject } = createDelayedPromise(); this.events.once(engineEvent("pairing_ping", id), ({ error }) => { if (error) reject(error); @@ -320,7 +320,7 @@ export class Pairing implements IPairing { // where pairing_ping listener is not yet initialized setTimeout(() => { if (isJsonRpcResult(payload)) { - this.events.emit(engineEvent("pairing_ping", id), {}); + this.events.emit(engineEvent("pairing_ping", id), Object.create(null)); } else if (isJsonRpcError(payload)) { this.events.emit(engineEvent("pairing_ping", id), { error: payload.error }); } diff --git a/packages/sign-client/src/controllers/engine.ts b/packages/sign-client/src/controllers/engine.ts index 304f45d90..bf369f705 100644 --- a/packages/sign-client/src/controllers/engine.ts +++ b/packages/sign-client/src/controllers/engine.ts @@ -133,8 +133,8 @@ export class Engine extends IEngine { const connectParams = { ...params, - requiredNamespaces: params.requiredNamespaces || {}, - optionalNamespaces: params.optionalNamespaces || {}, + requiredNamespaces: params.requiredNamespaces || Object.create(null), + optionalNamespaces: params.optionalNamespaces || Object.create(null), }; await this.isValidConnect(connectParams); const { pairingTopic, requiredNamespaces, optionalNamespaces, sessionProperties, relays } = @@ -328,7 +328,11 @@ export class Engine extends IEngine { await this.isInitialized(); await this.isValidExtend(params); const { topic } = params; - const id = await this.sendRequest({ topic, method: "wc_sessionExtend", params: {} }); + const id = await this.sendRequest({ + topic, + method: "wc_sessionExtend", + params: Object.create(null), + }); const { done: acknowledged, resolve, reject } = createDelayedPromise(); this.events.once(engineEvent("session_extend", id), ({ error }) => { if (error) reject(error); @@ -395,7 +399,11 @@ export class Engine extends IEngine { await this.isValidPing(params); const { topic } = params; if (this.client.session.keys.includes(topic)) { - const id = await this.sendRequest({ topic, method: "wc_sessionPing", params: {} }); + const id = await this.sendRequest({ + topic, + method: "wc_sessionPing", + params: Object.create(null), + }); const { done, resolve, reject } = createDelayedPromise(); this.events.once(engineEvent("session_ping", id), ({ error }) => { if (error) reject(error); @@ -856,7 +864,7 @@ export class Engine extends IEngine { const { id } = payload; if (isJsonRpcResult(payload)) { await this.client.session.update(topic, { acknowledged: true }); - this.events.emit(engineEvent("session_approve", id), {}); + this.events.emit(engineEvent("session_approve", id), Object.create(null)); } else if (isJsonRpcError(payload)) { await this.client.session.delete(topic, getSdkError("USER_DISCONNECTED")); this.events.emit(engineEvent("session_approve", id), { error: payload.error }); @@ -898,7 +906,7 @@ export class Engine extends IEngine { private onSessionUpdateResponse: EnginePrivate["onSessionUpdateResponse"] = (_topic, payload) => { const { id } = payload; if (isJsonRpcResult(payload)) { - this.events.emit(engineEvent("session_update", id), {}); + this.events.emit(engineEvent("session_update", id), Object.create(null)); } else if (isJsonRpcError(payload)) { this.events.emit(engineEvent("session_update", id), { error: payload.error }); } @@ -923,7 +931,7 @@ export class Engine extends IEngine { private onSessionExtendResponse: EnginePrivate["onSessionExtendResponse"] = (_topic, payload) => { const { id } = payload; if (isJsonRpcResult(payload)) { - this.events.emit(engineEvent("session_extend", id), {}); + this.events.emit(engineEvent("session_extend", id), Object.create(null)); } else if (isJsonRpcError(payload)) { this.events.emit(engineEvent("session_extend", id), { error: payload.error }); } @@ -947,7 +955,7 @@ export class Engine extends IEngine { // where session_ping listener is not yet initialized setTimeout(() => { if (isJsonRpcResult(payload)) { - this.events.emit(engineEvent("session_ping", id), {}); + this.events.emit(engineEvent("session_ping", id), Object.create(null)); } else if (isJsonRpcError(payload)) { this.events.emit(engineEvent("session_ping", id), { error: payload.error }); } diff --git a/packages/utils/src/namespaces.ts b/packages/utils/src/namespaces.ts index 95481bb86..7f4fd5870 100644 --- a/packages/utils/src/namespaces.ts +++ b/packages/utils/src/namespaces.ts @@ -54,7 +54,7 @@ export function getRequiredNamespacesFromNamespaces( const validNamespacesError = isValidNamespaces(namespaces, caller); if (validNamespacesError) throw new Error(validNamespacesError.message); - const required = {}; + const required = Object.create(null); for (const [namespace, values] of Object.entries(namespaces)) { required[namespace] = { methods: values.methods, @@ -84,14 +84,14 @@ export function buildApprovedNamespaces( params: BuildApprovedNamespacesParams, ): SessionTypes.Namespaces { const { - proposal: { requiredNamespaces, optionalNamespaces = {} }, + proposal: { requiredNamespaces, optionalNamespaces = Object.create(null) }, supportedNamespaces, } = params; const normalizedRequired = normalizeNamespaces(requiredNamespaces); const normalizedOptional = normalizeNamespaces(optionalNamespaces); // build approved namespaces - const namespaces = {}; + const namespaces = Object.create(null); Object.keys(supportedNamespaces).forEach((namespace) => { const supportedChains = supportedNamespaces[namespace].chains; const supportedMethods = supportedNamespaces[namespace].methods; @@ -116,7 +116,7 @@ export function buildApprovedNamespaces( const err = isConformingNamespaces(requiredNamespaces, namespaces, "approve()"); if (err) throw new Error(err.message); - const approvedNamespaces = {}; + const approvedNamespaces = Object.create(null); // if both required & optional namespaces are empty, return all supported namespaces by the wallet if (!Object.keys(requiredNamespaces).length && !Object.keys(optionalNamespaces).length) @@ -212,7 +212,7 @@ export function parseNamespaceKey(namespace: string) { export function normalizeNamespaces( namespaces: ProposalTypes.RequiredNamespaces, ): ProposalTypes.RequiredNamespaces { - const normalizedNamespaces = {} as ProposalTypes.RequiredNamespaces; + const normalizedNamespaces = Object.create(null) as ProposalTypes.RequiredNamespaces; if (!isValidObject(namespaces)) return normalizedNamespaces; for (const [key, values] of Object.entries(namespaces)) { const chains = isCaipNamespace(key) ? [key] : values.chains; diff --git a/packages/utils/src/uri.ts b/packages/utils/src/uri.ts index 39ba64c95..b1ca34324 100644 --- a/packages/utils/src/uri.ts +++ b/packages/utils/src/uri.ts @@ -45,7 +45,7 @@ export function parseTopic(topic: string): string { export function formatRelayParams(relay: RelayerTypes.ProtocolOptions, delimiter = "-") { const prefix = "relay"; - const params: any = {}; + const params: any = Object.create(null); Object.keys(relay).forEach((key) => { const k = prefix + delimiter + key; if (relay[key]) { diff --git a/packages/web3wallet/src/controllers/engine.ts b/packages/web3wallet/src/controllers/engine.ts index ed8633317..fdf90c25d 100644 --- a/packages/web3wallet/src/controllers/engine.ts +++ b/packages/web3wallet/src/controllers/engine.ts @@ -10,8 +10,8 @@ export class Engine extends IWeb3WalletEngine { constructor(client: IWeb3WalletEngine["client"]) { super(client); // initialized in init() - this.signClient = {} as any; - this.authClient = {} as any; + this.signClient = Object.create(null) as any; + this.authClient = Object.create(null) as any; } public init = async () => {