mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
fix(core): Filter out prototype and constructor lookups in expressions (#10382)
This commit is contained in:
@@ -74,7 +74,9 @@ for (const evaluator of ['tmpl', 'tournament'] as const) {
|
||||
expect(evaluate('={{Reflect}}')).toEqual({});
|
||||
expect(evaluate('={{Proxy}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{constructor}}')).toEqual({});
|
||||
expect(() => evaluate('={{constructor}}')).toThrowError(
|
||||
new ExpressionError('Cannot access "constructor" due to security concerns'),
|
||||
);
|
||||
|
||||
expect(evaluate('={{escape}}')).toEqual({});
|
||||
expect(evaluate('={{unescape}}')).toEqual({});
|
||||
@@ -166,7 +168,7 @@ for (const evaluator of ['tmpl', 'tournament'] as const) {
|
||||
const testFn = jest.fn();
|
||||
Object.assign(global, { testFn });
|
||||
expect(() => evaluate("={{ Date['constructor']('testFn()')()}}")).toThrowError(
|
||||
new ExpressionError('Arbitrary code execution detected'),
|
||||
new ExpressionError('Cannot access "constructor" due to security concerns'),
|
||||
);
|
||||
expect(testFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
84
packages/workflow/test/ExpressionSandboxing.test.ts
Normal file
84
packages/workflow/test/ExpressionSandboxing.test.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { PrototypeSanitizer, sanitizer } from '@/ExpressionSandboxing';
|
||||
import { Tournament } from '@n8n/tournament';
|
||||
|
||||
const tournament = new Tournament(
|
||||
(e) => {
|
||||
throw e;
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
before: [],
|
||||
after: [PrototypeSanitizer],
|
||||
},
|
||||
);
|
||||
|
||||
const errorRegex = /^Cannot access ".*" due to security concerns$/;
|
||||
|
||||
describe('PrototypeSanitizer', () => {
|
||||
describe('Static analysis', () => {
|
||||
it('should not allow access to __proto__', () => {
|
||||
expect(() => {
|
||||
tournament.execute('{{ ({}).__proto__.__proto__ }}', {});
|
||||
}).toThrowError(errorRegex);
|
||||
|
||||
expect(() => {
|
||||
tournament.execute('{{ ({})["__proto__"]["__proto__"] }}', {});
|
||||
}).toThrowError(errorRegex);
|
||||
});
|
||||
|
||||
it('should not allow access to prototype', () => {
|
||||
expect(() => {
|
||||
tournament.execute('{{ Number.prototype }}', { Number });
|
||||
}).toThrowError(errorRegex);
|
||||
|
||||
expect(() => {
|
||||
tournament.execute('{{ Number["prototype"] }}', { Number });
|
||||
}).toThrowError(errorRegex);
|
||||
});
|
||||
|
||||
it('should not allow access to constructor', () => {
|
||||
expect(() => {
|
||||
tournament.execute('{{ Number.constructor }}', {
|
||||
__sanitize: sanitizer,
|
||||
Number,
|
||||
});
|
||||
}).toThrowError(errorRegex);
|
||||
|
||||
expect(() => {
|
||||
tournament.execute('{{ Number["constructor"] }}', {
|
||||
__sanitize: sanitizer,
|
||||
Number,
|
||||
});
|
||||
}).toThrowError(errorRegex);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Runtime', () => {
|
||||
it('should not allow access to __proto__', () => {
|
||||
expect(() => {
|
||||
tournament.execute('{{ ({})["__" + (() => "proto")() + "__"] }}', {
|
||||
__sanitize: sanitizer,
|
||||
});
|
||||
}).toThrowError(errorRegex);
|
||||
});
|
||||
|
||||
it('should not allow access to prototype', () => {
|
||||
expect(() => {
|
||||
tournament.execute('{{ Number["pro" + (() => "toty")() + "pe"] }}', {
|
||||
__sanitize: sanitizer,
|
||||
Number,
|
||||
});
|
||||
}).toThrowError(errorRegex);
|
||||
});
|
||||
|
||||
it('should not allow access to constructor', () => {
|
||||
expect(() => {
|
||||
tournament.execute('{{ Number["cons" + (() => "truc")() + "tor"] }}', {
|
||||
__sanitize: sanitizer,
|
||||
Number,
|
||||
});
|
||||
}).toThrowError(errorRegex);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user