-
-
Notifications
You must be signed in to change notification settings - Fork 87
Description
Detail Bug Report
Summary
- Context: The
function.jsmodule executes user code in an isolated sandbox by callingisolated-functionwith security options including permissions and dependency whitelists. - Bug: The code unconditionally overrides the entire
allowobject when passing options toisolated-function, discarding anyallow.dependenciesorallow.permissionsthat were provided invmOpts. - Actual vs. expected: When
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. - 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.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 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.