n8n-io/n8n · error · ExpressionExtensionError

Cannot access "${name}" via expression extension due to secu

Error message

Cannot access "${name}" via expression extension due to security concerns

What it means

n8n sandbox-blocks a hardcoded set of unsafe property names (`__proto__`, `constructor`, `caller`, `arguments`, `__defineGetter__`/`__defineSetter__`, `getBuiltinModule`, `dlopen`, `execve`, `loadEnvFile`, ...) from being dispatched as expression extensions. This is a deliberate hardening to prevent prototype pollution and access to dangerous Node primitives from inside an expression.

Source

Thrown at packages/@n8n/expression-runtime/src/extensions/extend.ts:82

	'_linkedBinding',
	'_load',
	'prepareStackTrace',
	'__lookupGetter__',
	'__lookupSetter__',
	'__defineGetter__',
	'__defineSetter__',
	'caller',
	'arguments',
	'getBuiltinModule',
	'dlopen',
	'execve',
	'loadEnvFile',
]);

function findExtendedFunction(input: unknown, functionName: string): FoundFunction | undefined {
	const name = typeof functionName === 'string' ? functionName : String(functionName);
	if (UNSAFE_PROPERTY_NAMES.has(name)) {
		throw new ExpressionExtensionError(
			`Cannot access "${name}" via expression extension due to security concerns`,
		);
	}

	// eslint-disable-next-line @typescript-eslint/no-restricted-types
	let foundFunction: Function | undefined;
	if (Array.isArray(input)) {
		foundFunction = arrayExtensions.functions[name];
	} else if (isDate(input) && name !== 'toDate' && name !== 'toDateTime') {
		// If it's a string date (from $json), convert it to a Date object,
		// unless that function is `toDate`, since `toDate` does something
		// very different on date objects
		input = new Date(input as string);
		foundFunction = dateExtensions.functions[name];
	} else if (typeof input === 'string') {
		foundFunction = stringExtensions.functions[name];
	} else if (typeof input === 'number') {
		foundFunction = numberExtensions.functions[name];

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Do not access these property names through expressions.
  2. Move the logic into a Code node where full (sandboxed) JS is available, and only return primitive values back into the workflow.
  3. Sanitize untrusted input before it reaches an expression.

Example fix

// before
{{ $json.foo.constructor('return process')() }}
// after
// move the computation into a Code node; do not reach through constructors in expressions
Defensive patterns

Strategy: validation

Validate before calling

const UNSAFE = new Set(['__proto__','constructor','prototype','caller','arguments','__defineGetter__','__defineSetter__','getBuiltinModule','dlopen','execve','loadEnvFile']);
const name = $json.methodName;
if (typeof name === 'string' && UNSAFE.has(name)) {
  throw new Error(`Refusing to dispatch blocked property: ${name}`);
}
return $json;

Type guard

const isSafePropertyName = (name: string): boolean =>
  !['__proto__','constructor','prototype','caller','arguments','__defineGetter__','__defineSetter__','getBuiltinModule','dlopen','execve','loadEnvFile'].includes(name);

Prevention

When it happens

Trigger: Invoking any blocked name as an extension method: `{{ $json.foo.constructor() }}`, `{{ $json.bar.__proto__ }}`, `{{ $json.x.dlopen() }}`, `{{ $json.y.loadEnvFile() }}`.

Common situations: Attempts at prototype-chain traversal in an expression; libraries/probes that walk `__proto__`; adversarial or untrusted input routed through an expression.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/1f4c1817d15e4bc7. Report an issue: GitHub.