Skip to content

fix(sandbox): don't crash disposing a QuickJS context with a pending bridge call - #10380

Open
kwburns-kong wants to merge 2 commits into
developfrom
sec/sandbox-async
Open

fix(sandbox): don't crash disposing a QuickJS context with a pending bridge call#10380
kwburns-kong wants to merge 2 commits into
developfrom
sec/sandbox-async

Conversation

@kwburns-kong

Copy link
Copy Markdown
Contributor

What this PR does

This PR adds two sandbox fixes:

  • runTagInSandbox unconditionally disposed its QuickJS context, including when the sandbox's own timeout fired while a __hostBridge call (any granted async capability i.e network, fs-read, storage, etc.) was still outstanding. That left a live promise/continuation referenced inside the runtime, and freeing it tripped a fatal QuickJS engine assertion (JS_FreeRuntime's list_empty(&rt->gc_obj_list) check) instead of the intended "Template tag sandbox timed out" error. Reachable by any plugin capability that's simply slow.
  • A bridge handler returning a non-JSON-serializable value (e.g. a circular reference) escaped as a process-level unhandled rejection instead of a catchable tag error.

Fix

  • Track in-flight bridge calls per render (pendingBridgeCalls).
  • Force-settle them (reject + drain pending jobs) before disposing the context, on timeout and as a finally-block backstop.
  • Guard the bridge settle continuation so a call resolving after the context is already gone, or a non-serializable return value, surfaces as a normal tag error instead of an unhandled rejection.

No change to the error message callers see on timeout.

Test plan

  • packages/insomnia/src/templating/sandbox/async-boundary.regression.test.ts rewritten to assert the fixed behavior.
  • Full sandbox suite: 14 files / 177 tests pass.
  • Full package suite: 157 files / 2255 tests pass.
  • eslint / tsc --noEmit clean.
  • Independently re-verified with a negative control (reverting source file reproduces the old crash; restoring it passes again).

… a dispose-vs-pending-bridge-call defect

Audits the sandbox's async/reentrancy surface: disposing a QuickJS context
while a __hostBridge call is still pending trips a fatal engine assertion
in JS_FreeRuntime instead of a clean timeout error. Also pins three
ruled-out hypotheses from the same pass (concurrent-render job-queue
isolation, guest-internal unhandled-rejection safety, and marshal-boundary
purity) so future reviews don't re-derive them. Full write-up recorded in
the local (gist-backed, non-committed) SANDBOX-SECURITY-FINDINGS.md tracker.
…out QuickJS context

runTagInSandbox disposed its QuickJSContext unconditionally, including when
the sandbox's own timeout fired while a __hostBridge call was still
outstanding. That left a live promise/continuation referenced inside the
runtime, and freeing it (ctx.dispose()) tripped a fatal QuickJS engine
assertion (JS_FreeRuntime's list_empty(&rt->gc_obj_list) check) instead of
the intended clean timeout error.

Track in-flight bridge calls per render and force them to a settled state
(rejecting outstanding ones, draining the resulting jobs) before disposing,
so the runtime's GC list is empty by the time it's freed. Also guard the
bridge settle continuation itself so a call that resolves after the context
is already gone, or whose return value isn't JSON-serializable, surfaces as
an ordinary catchable error instead of a process-level unhandled rejection.
@github-actions

Copy link
Copy Markdown

✅ Circular References Report

Generated at: 2026-08-11T20:20:17.853Z
Status: ✅ NO CHANGE

Summary

Metric Base (develop) PR Change
Total Circular References 9 9 0 (0.00%)
Click to view all circular references in PR (9)
insomnia-inso/src/db/models/types.ts -> insomnia-inso/src/db/types.ts
insomnia/src/main/prompt-bridge.ts -> insomnia/src/main/window-utils.ts -> insomnia/src/main/plugin-window.ts
insomnia/src/main/window-utils.ts -> insomnia/src/main/plugin-window.ts
insomnia/src/network/network.ts -> insomnia-scripting-environment/src/objects/index.ts -> insomnia-scripting-environment/src/objects/collection.ts -> insomnia-scripting-environment/src/objects/response.ts
insomnia/src/network/network.ts -> insomnia/src/common/render.ts
insomnia/src/ui/components/settings/import-export.tsx -> insomnia/src/ui/components/modals/export-requests-modal.tsx
insomnia/src/ui/components/tabs/tab-list.tsx -> insomnia/src/ui/components/tabs/tab.tsx
insomnia/src/ui/components/templating/tag-editor-arg-sub-form.tsx -> insomnia/src/ui/components/templating/external-vault/external-vault-form.tsx
insomnia/src/ui/components/viewers/response-viewer.tsx -> insomnia/src/ui/components/viewers/response-multipart-viewer.tsx
Click to view all circular references in base branch (9)
insomnia-inso/src/db/models/types.ts -> insomnia-inso/src/db/types.ts
insomnia/src/main/prompt-bridge.ts -> insomnia/src/main/window-utils.ts -> insomnia/src/main/plugin-window.ts
insomnia/src/main/window-utils.ts -> insomnia/src/main/plugin-window.ts
insomnia/src/network/network.ts -> insomnia-scripting-environment/src/objects/index.ts -> insomnia-scripting-environment/src/objects/collection.ts -> insomnia-scripting-environment/src/objects/response.ts
insomnia/src/network/network.ts -> insomnia/src/common/render.ts
insomnia/src/ui/components/settings/import-export.tsx -> insomnia/src/ui/components/modals/export-requests-modal.tsx
insomnia/src/ui/components/tabs/tab-list.tsx -> insomnia/src/ui/components/tabs/tab.tsx
insomnia/src/ui/components/templating/tag-editor-arg-sub-form.tsx -> insomnia/src/ui/components/templating/external-vault/external-vault-form.tsx
insomnia/src/ui/components/viewers/response-viewer.tsx -> insomnia/src/ui/components/viewers/response-multipart-viewer.tsx

Analysis

No Change: This PR does not introduce or remove any circular references.


This report was generated automatically by comparing against the develop branch.

@kwburns-kong
kwburns-kong requested a review from jackkav August 12, 2026 02:12
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