diff --git a/packages/snaps-controllers/src/services/iframe/IframeExecutionService.ts b/packages/snaps-controllers/src/services/iframe/IframeExecutionService.ts index 71812eb559..1986de58d2 100644 --- a/packages/snaps-controllers/src/services/iframe/IframeExecutionService.ts +++ b/packages/snaps-controllers/src/services/iframe/IframeExecutionService.ts @@ -30,7 +30,17 @@ export class IframeExecutionService extends AbstractExecutionService { } protected terminateJob(jobWrapper: TerminateJobArgs): void { - document.getElementById(jobWrapper.id)?.remove(); + const iframe = document.getElementById( + jobWrapper.id, + ) as HTMLIFrameElement | null; + if (iframe) { + // Navigate to about:blank before removing to ensure the browser + // unloads the previous document and cleans up its event listeners. + // Without this, Firefox may keep the detached iframe's document alive + // with all its event listeners, causing a memory leak. + iframe.src = 'about:blank'; + iframe.remove(); + } } protected async initEnvStream(snapId: string): Promise<{ diff --git a/packages/snaps-execution-environments/src/common/BaseSnapExecutor.ts b/packages/snaps-execution-environments/src/common/BaseSnapExecutor.ts index 3818439f46..3feb6edac2 100644 --- a/packages/snaps-execution-environments/src/common/BaseSnapExecutor.ts +++ b/packages/snaps-execution-environments/src/common/BaseSnapExecutor.ts @@ -486,6 +486,19 @@ export class BaseSnapExecutor { data.runningEvaluations.forEach((evaluation) => evaluation.stop()), ); this.snapData.clear(); + + // Clean up global error handlers to prevent memory leaks. + // Without this, the event listeners keep references to the executor + // and prevent the iframe from being garbage collected. + if (this.snapPromiseErrorHandler) { + removeEventListener('unhandledrejection', this.snapPromiseErrorHandler); + this.snapPromiseErrorHandler = undefined; + } + + if (this.snapErrorHandler) { + removeEventListener('error', this.snapErrorHandler); + this.snapErrorHandler = undefined; + } } // TODO: Either fix this lint violation or explain why it's necessary to