Skip to content

Commit bcc5168

Browse files
committed
fix(this): fix 'this' exposing the global object inside sandboxed code
1 parent ef32200 commit bcc5168

File tree

4 files changed

+60
-15
lines changed

4 files changed

+60
-15
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,37 @@ const code = compiler.compileCode('console.log(localVariable)')
132132
code({}, ['console', 'localVariable'])
133133
```
134134

135+
#### 'this' inside the sandboxed code
136+
137+
`this` points to the sandbox inside the sandboxed code.
138+
139+
```js
140+
const compiler = require('@risingstack/nx-compile')
141+
142+
const message = 'local message'
143+
const code = compiler.compileCode('console.log(this.message)')
144+
145+
// outputs 'sandboxed message' to the console
146+
code({message: 'sandboxed message'}, ['console'])
147+
```
148+
149+
#### functions defined inside the sandboxed code
150+
151+
Functions defined inside the sandboxed code are also sandboxed.
152+
153+
```js
154+
const compiler = require('@risingstack/nx-compile')
155+
156+
const message = 'local message'
157+
const rawCode = '({}).__proto__.func = function() { return message }'
158+
const code = compiler.compileCode(rawCode)
159+
160+
code({message: 'sandboxed message'})
161+
162+
// outputs 'sandboxed message' to the console
163+
console.log(({}).func())
164+
```
165+
135166
## Contributions
136167

137168
This library has the very specific purpose of supporting the [NX framework](https://github.com/RisingStack/nx-framework). Features should only be added, if they are used by the framework. Otherwise please fork.

compiler.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ function compileCode (src) {
3131
}
3232

3333
if (!sandboxProxies.has(sandbox)) {
34-
sandboxProxies.set(sandbox, new Proxy(sandbox, {has: has, get: get}))
34+
sandboxProxies.set(sandbox, new Proxy(sandbox, {has, get}))
3535
}
3636
currentAllowedGlobals = allowedGlobals
37+
const sandboxProxy = sandboxProxies.get(sandbox)
3738

3839
let result
3940
try {
40-
result = code(sandboxProxies.get(sandbox))
41+
result = code.call(sandboxProxy, sandboxProxy)
4142
} finally {
4243
currentAllowedGlobals = undefined
4344
}

compiler.test.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ const localProp = 1
99

1010
describe('nx-compile', () => {
1111
describe('compileCode', () => {
12-
it('should execute code in a sandbox', () => {
13-
const code = compiler.compileCode('return prop1 + prop2')
14-
const value = code({prop1: 1, prop2: 2})
15-
expect(value).to.equal(3)
16-
})
17-
1812
it('should throw TypeError on invalid source argument', () => {
1913
expect(() => compiler.compileCode({})).to.throw(TypeError)
2014
expect(() => compiler.compileCode()).to.throw(TypeError)
@@ -23,12 +17,6 @@ describe('nx-compile', () => {
2317
})
2418

2519
describe('compileExpression', () => {
26-
it('should execute expression in a sandbox', () => {
27-
const expression = compiler.compileExpression('prop1 + prop2')
28-
const value = expression({prop1: 1, prop2: 2})
29-
expect(value).to.equal(3)
30-
})
31-
3220
it('should throw TypeError on invalid source argument', () => {
3321
expect(() => compiler.compileExpression({})).to.throw(TypeError)
3422
expect(() => compiler.compileExpression()).to.throw(TypeError)
@@ -37,6 +25,31 @@ describe('nx-compile', () => {
3725
})
3826

3927
describe('returned function (compiled code or expression)', () => {
28+
it('should execute in a sandbox', () => {
29+
const expression = compiler.compileExpression('prop1 + prop2')
30+
const value = expression({prop1: 1, prop2: 2})
31+
expect(value).to.equal(3)
32+
})
33+
34+
it('should not expose globals to the sandbox', () => {
35+
const expression = compiler.compileExpression('prop1')
36+
const value = expression({})
37+
expect(value).to.equal(undefined)
38+
})
39+
40+
it('should not expose globals inside functions defined in the passed code', () => {
41+
const rawCode = '({}).__proto__.evil = function() { return prop1 + prop2 }'
42+
const code = compiler.compileCode(rawCode)
43+
code({prop1: 1, prop2: 2})
44+
expect(({}).evil()).to.equal(3)
45+
})
46+
47+
it('"this" should be the sandbox instead of the global object', () => {
48+
const expression = compiler.compileExpression('this.prop1 + this.prop2')
49+
const value = expression({prop1: 1, prop2: 2}, [])
50+
expect(value).to.equal(3)
51+
})
52+
4053
it('should expose specified globals to the sandbox', () => {
4154
const expression = compiler.compileExpression('prop1 + prop2')
4255
const value = expression({}, ['prop1', 'prop2'])

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@risingstack/nx-compile",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "Execution of strings as code in a secure, sandboxed environment.",
55
"main": "compiler.js",
66
"scripts": {

0 commit comments

Comments
 (0)