{"record":{"id":"f3847e97d1024cd0","repo":"n8n-io/n8n","slug":"dynamic-property-access-is-not-allowed-use-static","errorCode":null,"errorMessage":"Dynamic property access is not allowed. Use static property names.","messagePattern":"Dynamic property access is not allowed\\. Use static property names\\.","errorType":"exception","errorClass":"SecurityError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/ast-interpreter/validators.ts","lineNumber":328,"sourceCode":"\tif (node.callee.type === 'MemberExpression') {\n\t\tconst memberExpr = node.callee;\n\t\tif (memberExpr.property.type === 'Identifier' && memberExpr.property.name === 'constructor') {\n\t\t\tthrow new SecurityError('constructor access', node.loc ?? undefined, sourceCode);\n\t\t}\n\t}\n}\n\n/**\n * Validate a member expression.\n * @throws SecurityError if the access is dangerous\n */\nexport function validateMemberExpression(node: MemberExpression, sourceCode: string): void {\n\t// Reject dynamic property access obj[expr] (computed access)\n\t// Allow obj.property (non-computed)\n\tif (node.computed) {\n\t\t// Allow simple literal keys like obj[\"key\"] or obj[0]\n\t\tif (node.property.type !== 'Literal') {\n\t\t\tthrow new SecurityError(\n\t\t\t\t'computed-member-access',\n\t\t\t\tnode.loc ?? undefined,\n\t\t\t\tsourceCode,\n\t\t\t\t'Dynamic property access is not allowed. Use static property names.',\n\t\t\t);\n\t\t}\n\t}\n\n\t// Check for dangerous property names (both dot notation and literal keys)\n\tconst propName =\n\t\tnode.property.type === 'Identifier'\n\t\t\t? node.property.name\n\t\t\t: node.property.type === 'Literal' && typeof node.property.value === 'string'\n\t\t\t\t? node.property.value\n\t\t\t\t: undefined;\n\n\tif (\n\t\tpropName !== undefined &&","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/ast-interpreter/validators.ts#L310-L346","documentation":"Thrown by validateMemberExpression when a member access is computed (`obj[expr]`) AND the expression is not a Literal. Dynamic/computed property access with a non-literal key is blocked because the interpreter cannot statically verify it is safe. Literal keys like `obj['key']` or `arr[0]` are allowed; variable keys like `obj[name]` are not. The SecurityError is constructed with a custom detail message.","triggerScenarios":"SDK code containing `obj[variableName]`, `arr[i]` where `i` is not a numeric literal, `obj[someExpression]`, or `map[key]` with a computed non-literal key. Reading OR writing — validateMemberExpression runs for both.","commonSituations":"Dynamic lookups in configuration objects; indexed access in what was a loop; using a variable to select a property; porting dictionary-lookup code.","solutions":["Replace dynamic key access with a static property name: `obj.fixedKey`.","If the key is a known constant, use a literal: `obj['fixedKey']` or `arr[0]`.","Refactor dynamic lookup into a conditional or a fixed map defined as an object literal with all keys spelled out.","Move genuinely dynamic lookups to a Code node where computed access is permitted."],"exampleFix":"// before\nconst key = 'dynamic' + suffix;\nconst val = obj[key];\n\n// after\nconst val = obj.fixedDynamicSuffix;  // static name\n// or, if the key is a fixed string:\nconst val = obj['fixedKey'];","handlingStrategy":"validation","validationCode":"import { parseSDKCode } from '@n8n/workflow-sdk/ast-interpreter/parser';\n\nfunction findComputedNonLiteralAccess(code: string): string[] {\n  const issues: string[] = [];\n  const ast = parseSDKCode(code);\n  JSON.stringify(ast, (k, v) => {\n    if (v?.type === 'MemberExpression' && v.computed && v.property?.type !== 'Literal') {\n      issues.push(`Computed non-literal access at line ${v.loc?.start.line}: use a static name or literal key`);\n    }\n    return v;\n  });\n  return issues;\n}","typeGuard":"function isLiteralKey(memberNode: { computed: boolean; property: { type?: string } }): boolean {\n  return !memberNode.computed || memberNode.property.type === 'Literal';\n}","tryCatchPattern":"import { interpretSDKCode } from '@n8n/workflow-sdk/ast-interpreter/interpreter';\nimport { SecurityError } from '@n8n/workflow-sdk/ast-interpreter/errors';\n\ntry {\n  interpretSDKCode(code, sdkFunctions);\n} catch (e) {\n  if (e instanceof SecurityError && e.pattern === 'computed-member-access') {\n    // instruct: replace obj[var] with obj.fixedKey or obj['literal']\n  }\n  throw e;\n}","preventionTips":["Ban computed member access in builder code via lint; require dot notation or literal keys.","Use `obj['fixedKey']` or `arr[0]` when a bracket is needed — both are allowed.","Move dictionary-style lookups to a Code node."],"tags":["sdk","validators","security","dynamic-access","computed-member"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}