Detail Bug Report
https://app.detail.dev/org_06887db3-bf54-40ab-976d-46c66ab2b840/bugs/bug_7d906711-8afc-44f8-b572-01046edcaed1
Summary
- Context: The
function.js module executes user code in an isolated sandbox by calling isolated-function with security options including permissions and dependency whitelists.
- Bug: The code unconditionally overrides the entire
allow object when passing options to isolated-function, discarding any allow.dependencies or allow.permissions that were provided in vmOpts.
- Actual vs. expected: When
vmOpts.allow.dependencies is provided to restrict which npm packages can be imported, this security restriction is silently ignored. Expected behavior is to merge the permissions while preserving the dependencies whitelist.
- Impact: This allows untrusted code to import and execute any npm package, bypassing dependency whitelisting intended for security.
Code with Bug
In packages/function/src/function.js:
module.exports = async ({
url,
code,
vmOpts,
browserWSEndpoint,
needsNetwork = template.isUsingPage(code),
source = template(code, needsNetwork),
...opts
}) => {
const permissions = needsNetwork && nodeMajor >= 25 ? ['net'] : []
const [fn, teardown] = isolatedFunction(source, {
...vmOpts,
allow: { permissions }, // <-- BUG 🔴 Completely replaces vmOpts.allow, discarding vmOpts.allow.dependencies
throwError: false
})
const result = await fn(url, browserWSEndpoint, opts)
await teardown()
return result
}
Explanation
Because ...vmOpts is applied first and then allow: { permissions } is set afterward, any vmOpts.allow object is overwritten. As a result:
vmOpts.allow.dependencies is dropped, so dependency whitelisting is not enforced.
vmOpts.allow.permissions is also replaced, causing unexpected permission behavior.
Evidence: a repro passing vmOpts.allow.dependencies: ['lodash'] while user code does require('fs') succeeds (returns { isFulfilled: true, value: 'success' }) instead of failing with a dependency-not-allowed error.
Exploit Scenario
An attacker (or any untrusted user code executed by this sandbox) can bypass an intended vmOpts.allow.dependencies whitelist and import arbitrary modules/packages (e.g., fs or other installed npm packages), even when the caller believes imports are restricted.
Recommended Fix
Merge allow rather than replacing it, preserving vmOpts.allow.dependencies and combining permissions:
const vmOptsAllow = vmOpts?.allow || {}
const [fn, teardown] = isolatedFunction(source, {
...vmOpts,
allow: {
...vmOptsAllow,
permissions: [
...(vmOptsAllow.permissions || []),
...permissions
]
},
throwError: false
})
History
This bug was introduced in commit a136140. The commit upgraded the isolated-function dependency from v0.1.46 to v0.1.47 (changing allow from an array to an object), and updated the call site to allow: { permissions } without merging with vmOpts.allow, discarding allow.dependencies.
Detail Bug Report
https://app.detail.dev/org_06887db3-bf54-40ab-976d-46c66ab2b840/bugs/bug_7d906711-8afc-44f8-b572-01046edcaed1
Summary
function.jsmodule executes user code in an isolated sandbox by callingisolated-functionwith security options including permissions and dependency whitelists.allowobject when passing options toisolated-function, discarding anyallow.dependenciesorallow.permissionsthat were provided invmOpts.vmOpts.allow.dependenciesis provided to restrict which npm packages can be imported, this security restriction is silently ignored. Expected behavior is to merge the permissions while preserving the dependencies whitelist.Code with Bug
In
packages/function/src/function.js:Explanation
Because
...vmOptsis applied first and thenallow: { permissions }is set afterward, anyvmOpts.allowobject is overwritten. As a result:vmOpts.allow.dependenciesis dropped, so dependency whitelisting is not enforced.vmOpts.allow.permissionsis also replaced, causing unexpected permission behavior.Evidence: a repro passing
vmOpts.allow.dependencies: ['lodash']while user code doesrequire('fs')succeeds (returns{ isFulfilled: true, value: 'success' }) instead of failing with a dependency-not-allowed error.Exploit Scenario
An attacker (or any untrusted user code executed by this sandbox) can bypass an intended
vmOpts.allow.dependencieswhitelist and import arbitrary modules/packages (e.g.,fsor other installed npm packages), even when the caller believes imports are restricted.Recommended Fix
Merge
allowrather than replacing it, preservingvmOpts.allow.dependenciesand combining permissions:History
This bug was introduced in commit a136140. The commit upgraded the
isolated-functiondependency from v0.1.46 to v0.1.47 (changingallowfrom an array to an object), and updated the call site toallow: { permissions }without merging withvmOpts.allow, discardingallow.dependencies.