fix(core): Disallow code generation in task runner (#12522)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions

This commit is contained in:
Tomi Turtiainen 2025-01-09 13:27:17 +02:00 committed by GitHub
parent 46f13cfca9
commit 35b618098b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 23 additions and 12 deletions

View file

@ -4,7 +4,10 @@
"runner-type": "javascript",
"workdir": "/home/node",
"command": "/usr/local/bin/node",
"args": ["/usr/local/lib/node_modules/n8n/node_modules/@n8n/task-runner/dist/start.js"],
"args": [
"--disallow-code-generation-from-strings",
"/usr/local/lib/node_modules/n8n/node_modules/@n8n/task-runner/dist/start.js"
],
"allowed-env": [
"PATH",
"GENERIC_TIMEZONE",

View file

@ -302,6 +302,7 @@ describe('JsTaskRunner', () => {
['typeof clearInterval', 'function'],
['typeof clearImmediate', 'function'],
],
eval: [['eval("1+2")', 3]],
'JS built-ins': [
['typeof btoa', 'function'],
['typeof atob', 'function'],

View file

@ -19,7 +19,7 @@ import type {
} from 'n8n-workflow';
import * as a from 'node:assert';
import { inspect } from 'node:util';
import { runInNewContext, type Context } from 'node:vm';
import { type Context, createContext, runInContext } from 'node:vm';
import type { MainConfig } from '@/config/main-config';
import { UnsupportedFunctionError } from '@/js-task-runner/errors/unsupported-function.error';
@ -158,10 +158,8 @@ export class JsTaskRunner extends TaskRunner {
private getNativeVariables() {
return {
// Exposed Node.js globals in vm2
// Exposed Node.js globals
Buffer,
Function,
eval,
setTimeout,
setInterval,
setImmediate,
@ -205,7 +203,7 @@ export class JsTaskRunner extends TaskRunner {
signal.addEventListener('abort', abortHandler, { once: true });
const taskResult = runInNewContext(
const taskResult = runInContext(
`globalThis.global = globalThis; module.exports = async function VmCodeWrapper() {${settings.code}\n}()`,
context,
{ timeout: this.taskTimeout * 1000 },
@ -268,7 +266,7 @@ export class JsTaskRunner extends TaskRunner {
signal.addEventListener('abort', abortHandler);
const taskResult = runInNewContext(
const taskResult = runInContext(
`module.exports = async function VmCodeWrapper() {${settings.code}\n}()`,
context,
{ timeout: this.taskTimeout * 1000 },
@ -470,7 +468,7 @@ export class JsTaskRunner extends TaskRunner {
dataProxy: IWorkflowDataProxyData,
additionalProperties: Record<string, unknown> = {},
): Context {
const context: Context = {
return createContext({
[inspect.custom]: () => '[[ExecutionContext]]',
require: this.requireResolver,
module: {},
@ -480,8 +478,6 @@ export class JsTaskRunner extends TaskRunner {
...dataProxy,
...this.buildRpcCallObject(taskId),
...additionalProperties,
};
return context;
});
}
}

View file

@ -117,5 +117,16 @@ describe('TaskRunnerProcess', () => {
const options = spawnMock.mock.calls[0][2] as SpawnOptions;
expect(options.env).not.toHaveProperty('NODE_OPTIONS');
});
it('should use --disallow-code-generation-from-strings flag', async () => {
jest.spyOn(authService, 'createGrantToken').mockResolvedValue('grantToken');
await taskRunnerProcess.start();
expect(spawnMock.mock.calls[0].at(1)).toEqual([
'--disallow-code-generation-from-strings',
expect.stringContaining('/packages/@n8n/task-runner/dist/start.js'),
]);
});
});
});

View file

@ -106,7 +106,7 @@ export class TaskRunnerProcess extends TypedEmitter<TaskRunnerProcessEventMap> {
startNode(grantToken: string, taskBrokerUri: string) {
const startScript = require.resolve('@n8n/task-runner/start');
return spawn('node', [startScript], {
return spawn('node', ['--disallow-code-generation-from-strings', startScript], {
env: this.getProcessEnvVars(grantToken, taskBrokerUri),
});
}