mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
fix(core): Prevent arbitrary code execution via expressions (#6420)
This commit is contained in:
parent
2aef9de148
commit
da7ae2beef
|
@ -39,6 +39,18 @@ tmpl.tmpl.errorHandler = (error: Error) => {
|
|||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const AsyncFunction = (async () => {}).constructor as FunctionConstructor;
|
||||
|
||||
const fnConstructors = {
|
||||
sync: Function.prototype.constructor,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
async: AsyncFunction.prototype.constructor,
|
||||
mock: () => {
|
||||
throw new ExpressionError('Arbitrary code execution detected');
|
||||
},
|
||||
};
|
||||
|
||||
export class Expression {
|
||||
workflow: Workflow;
|
||||
|
||||
|
@ -315,6 +327,9 @@ export class Expression {
|
|||
data: IWorkflowDataProxyData,
|
||||
): tmpl.ReturnValue | undefined {
|
||||
try {
|
||||
[Function, AsyncFunction].forEach(({ prototype }) =>
|
||||
Object.defineProperty(prototype, 'constructor', { value: fnConstructors.mock }),
|
||||
);
|
||||
return tmpl.tmpl(expression, data);
|
||||
} catch (error) {
|
||||
if (error instanceof ExpressionError) {
|
||||
|
@ -352,6 +367,11 @@ export class Expression {
|
|||
|
||||
throw new Error(match.groups.msg);
|
||||
}
|
||||
} finally {
|
||||
Object.defineProperty(Function.prototype, 'constructor', { value: fnConstructors.sync });
|
||||
Object.defineProperty(AsyncFunction.prototype, 'constructor', {
|
||||
value: fnConstructors.async,
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,13 @@ describe('Expression', () => {
|
|||
expect(evaluate('={{Boolean(1)}}')).toEqual(Boolean(1));
|
||||
expect(evaluate('={{Symbol(1).toString()}}')).toEqual(Symbol(1).toString());
|
||||
});
|
||||
|
||||
it('should not able to do arbitrary code execution', () => {
|
||||
const testFn = jest.fn();
|
||||
Object.assign(global, { testFn });
|
||||
evaluate("={{ Date['constructor']('testFn()')()}}");
|
||||
expect(testFn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test all expression value fixtures', () => {
|
||||
|
|
Loading…
Reference in a new issue