isolated-function 0.1.47 → 0.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -155,7 +155,7 @@ await fn('🙌') // => true
155
155
  await teardown()
156
156
  ```
157
157
 
158
- If the code tries to require a package not in the allowed list, an `UntrustedDependencyError` is thrown **before** any npm install happens:
158
+ If the code tries to require a package not in the allowed list, a `DependencyUnallowedError` is thrown **before** any npm install happens:
159
159
 
160
160
  ```js
161
161
  const [fn, teardown] = isolatedFunction(
@@ -169,7 +169,7 @@ const [fn, teardown] = isolatedFunction(
169
169
  )
170
170
 
171
171
  await fn()
172
- // => UntrustedDependencyError: Dependency 'malicious-package' is not in the allowed list
172
+ // => DependencyUnallowedError: Dependency 'malicious-package' is not in the allowed list
173
173
  ```
174
174
 
175
175
  > **Security Note**: Even with the sandbox, arbitrary package installation is dangerous because npm packages can execute code during installation via `preinstall`/`postinstall` scripts. The `--ignore-scripts` flag is used to mitigate this, but providing an `allow.dependencies` whitelist is the recommended approach for running untrusted code.
package/package.json CHANGED
@@ -2,11 +2,12 @@
2
2
  "name": "isolated-function",
3
3
  "description": "Runs untrusted code in a Node.js v8 sandbox.",
4
4
  "homepage": "https://github.com/Kikobeats/isolated-function",
5
- "version": "0.1.47",
5
+ "version": "0.1.48",
6
6
  "types": "src/index.d.ts",
7
7
  "main": "src/index.js",
8
8
  "exports": {
9
- ".": "./src/index.js"
9
+ ".": "./src/index.js",
10
+ "./errors": "./src/errors.js"
10
11
  },
11
12
  "author": {
12
13
  "email": "hello@microlink.io",
@@ -41,4 +41,3 @@ module.exports = async (snippet, { tmpdir = tmpdirDefault, allow = {} } = {}) =>
41
41
 
42
42
  module.exports.detectDependencies = detectDependencies
43
43
  module.exports.transformDependencies = transformDependencies
44
- module.exports.UntrustedDependencyError = installDependencies.UntrustedDependencyError
@@ -3,6 +3,8 @@
3
3
  const { execSync } = require('child_process')
4
4
  const $ = require('tinyspawn')
5
5
 
6
+ const { DependencyNameError, DependencyUnallowedError } = require('../errors')
7
+
6
8
  const install = (() => {
7
9
  try {
8
10
  execSync('which pnpm', { stdio: ['pipe', 'pipe', 'ignore'] })
@@ -14,14 +16,6 @@ const install = (() => {
14
16
  }
15
17
  })()
16
18
 
17
- class UntrustedDependencyError extends Error {
18
- constructor (dependency) {
19
- super(`Dependency '${dependency}' is not in the allowed list`)
20
- this.name = 'UntrustedDependencyError'
21
- this.dependency = dependency
22
- }
23
- }
24
-
25
19
  const extractPackageName = dependency => {
26
20
  if (dependency.startsWith('@')) {
27
21
  const slashIndex = dependency.indexOf('/')
@@ -41,12 +35,19 @@ const extractPackageName = dependency => {
41
35
  }
42
36
 
43
37
  const validateDependencies = (dependencies, allowed) => {
38
+ // Always check for command injection, regardless of allow list
39
+ for (const dependency of dependencies) {
40
+ if (dependency.includes(' ')) {
41
+ throw new DependencyNameError(dependency)
42
+ }
43
+ }
44
+
44
45
  if (!allowed) return
45
46
 
46
47
  for (const dependency of dependencies) {
47
48
  const packageName = extractPackageName(dependency)
48
49
  if (!allowed.includes(packageName)) {
49
- throw new UntrustedDependencyError(packageName)
50
+ throw new DependencyUnallowedError(packageName)
50
51
  }
51
52
  }
52
53
  }
@@ -55,5 +56,3 @@ module.exports = async ({ dependencies, cwd, allow = {} }) => {
55
56
  validateDependencies(dependencies, allow.dependencies)
56
57
  return $(`${install} ${dependencies.join(' ')}`, { cwd, env: { ...process.env, CI: true } })
57
58
  }
58
-
59
- module.exports.UntrustedDependencyError = UntrustedDependencyError
package/src/errors.js ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ class IsolatedFunctionError extends Error {
4
+ constructor (message) {
5
+ super(message)
6
+ this.name = 'IsolatedFunctionError'
7
+ }
8
+ }
9
+
10
+ class DependencyNameError extends IsolatedFunctionError {
11
+ constructor (dependency) {
12
+ super(`Dependency '${dependency}' is not a valid npm package name`)
13
+ this.name = 'DependencyNameError'
14
+ this.code = 'EDEPENDENCYNAME'
15
+ this.dependency = dependency
16
+ }
17
+ }
18
+
19
+ class DependencyUnallowedError extends IsolatedFunctionError {
20
+ constructor (dependency) {
21
+ super(`Dependency '${dependency}' is not in the allowed list`)
22
+ this.name = 'DependencyUnallowedError'
23
+ this.code = 'EDEPENDENCYUNALLOWED'
24
+ this.dependency = dependency
25
+ }
26
+ }
27
+
28
+ module.exports = {
29
+ IsolatedFunctionError,
30
+ DependencyNameError,
31
+ DependencyUnallowedError
32
+ }