mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
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
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:
parent
46f13cfca9
commit
35b618098b
|
@ -4,7 +4,10 @@
|
||||||
"runner-type": "javascript",
|
"runner-type": "javascript",
|
||||||
"workdir": "/home/node",
|
"workdir": "/home/node",
|
||||||
"command": "/usr/local/bin/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": [
|
"allowed-env": [
|
||||||
"PATH",
|
"PATH",
|
||||||
"GENERIC_TIMEZONE",
|
"GENERIC_TIMEZONE",
|
||||||
|
|
|
@ -302,6 +302,7 @@ describe('JsTaskRunner', () => {
|
||||||
['typeof clearInterval', 'function'],
|
['typeof clearInterval', 'function'],
|
||||||
['typeof clearImmediate', 'function'],
|
['typeof clearImmediate', 'function'],
|
||||||
],
|
],
|
||||||
|
eval: [['eval("1+2")', 3]],
|
||||||
'JS built-ins': [
|
'JS built-ins': [
|
||||||
['typeof btoa', 'function'],
|
['typeof btoa', 'function'],
|
||||||
['typeof atob', 'function'],
|
['typeof atob', 'function'],
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type {
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import * as a from 'node:assert';
|
import * as a from 'node:assert';
|
||||||
import { inspect } from 'node:util';
|
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 type { MainConfig } from '@/config/main-config';
|
||||||
import { UnsupportedFunctionError } from '@/js-task-runner/errors/unsupported-function.error';
|
import { UnsupportedFunctionError } from '@/js-task-runner/errors/unsupported-function.error';
|
||||||
|
@ -158,10 +158,8 @@ export class JsTaskRunner extends TaskRunner {
|
||||||
|
|
||||||
private getNativeVariables() {
|
private getNativeVariables() {
|
||||||
return {
|
return {
|
||||||
// Exposed Node.js globals in vm2
|
// Exposed Node.js globals
|
||||||
Buffer,
|
Buffer,
|
||||||
Function,
|
|
||||||
eval,
|
|
||||||
setTimeout,
|
setTimeout,
|
||||||
setInterval,
|
setInterval,
|
||||||
setImmediate,
|
setImmediate,
|
||||||
|
@ -205,7 +203,7 @@ export class JsTaskRunner extends TaskRunner {
|
||||||
|
|
||||||
signal.addEventListener('abort', abortHandler, { once: true });
|
signal.addEventListener('abort', abortHandler, { once: true });
|
||||||
|
|
||||||
const taskResult = runInNewContext(
|
const taskResult = runInContext(
|
||||||
`globalThis.global = globalThis; module.exports = async function VmCodeWrapper() {${settings.code}\n}()`,
|
`globalThis.global = globalThis; module.exports = async function VmCodeWrapper() {${settings.code}\n}()`,
|
||||||
context,
|
context,
|
||||||
{ timeout: this.taskTimeout * 1000 },
|
{ timeout: this.taskTimeout * 1000 },
|
||||||
|
@ -268,7 +266,7 @@ export class JsTaskRunner extends TaskRunner {
|
||||||
|
|
||||||
signal.addEventListener('abort', abortHandler);
|
signal.addEventListener('abort', abortHandler);
|
||||||
|
|
||||||
const taskResult = runInNewContext(
|
const taskResult = runInContext(
|
||||||
`module.exports = async function VmCodeWrapper() {${settings.code}\n}()`,
|
`module.exports = async function VmCodeWrapper() {${settings.code}\n}()`,
|
||||||
context,
|
context,
|
||||||
{ timeout: this.taskTimeout * 1000 },
|
{ timeout: this.taskTimeout * 1000 },
|
||||||
|
@ -470,7 +468,7 @@ export class JsTaskRunner extends TaskRunner {
|
||||||
dataProxy: IWorkflowDataProxyData,
|
dataProxy: IWorkflowDataProxyData,
|
||||||
additionalProperties: Record<string, unknown> = {},
|
additionalProperties: Record<string, unknown> = {},
|
||||||
): Context {
|
): Context {
|
||||||
const context: Context = {
|
return createContext({
|
||||||
[inspect.custom]: () => '[[ExecutionContext]]',
|
[inspect.custom]: () => '[[ExecutionContext]]',
|
||||||
require: this.requireResolver,
|
require: this.requireResolver,
|
||||||
module: {},
|
module: {},
|
||||||
|
@ -480,8 +478,6 @@ export class JsTaskRunner extends TaskRunner {
|
||||||
...dataProxy,
|
...dataProxy,
|
||||||
...this.buildRpcCallObject(taskId),
|
...this.buildRpcCallObject(taskId),
|
||||||
...additionalProperties,
|
...additionalProperties,
|
||||||
};
|
});
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,5 +117,16 @@ describe('TaskRunnerProcess', () => {
|
||||||
const options = spawnMock.mock.calls[0][2] as SpawnOptions;
|
const options = spawnMock.mock.calls[0][2] as SpawnOptions;
|
||||||
expect(options.env).not.toHaveProperty('NODE_OPTIONS');
|
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'),
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -106,7 +106,7 @@ export class TaskRunnerProcess extends TypedEmitter<TaskRunnerProcessEventMap> {
|
||||||
startNode(grantToken: string, taskBrokerUri: string) {
|
startNode(grantToken: string, taskBrokerUri: string) {
|
||||||
const startScript = require.resolve('@n8n/task-runner/start');
|
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),
|
env: this.getProcessEnvVars(grantToken, taskBrokerUri),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue