n8n Vulnerable to Remote Code Execution via Expression Injection
Description
n8n is an open source workflow automation platform. Versions starting with 0.211.0 and prior to 1.120.4, 1.121.1, and 1.122.0 contain a critical Remote Code Execution (RCE) vulnerability in their workflow expression evaluation system. Under certain conditions, expressions supplied by authenticated users during workflow configuration may be evaluated in an execution context that is not sufficiently isolated from the underlying runtime. An authenticated attacker could abuse this behavior to execute arbitrary code with the privileges of the n8n process. Successful exploitation may lead to full compromise of the affected instance, including unauthorized access to sensitive data, modification of workflows, and execution of system-level operations. This issue has been fixed in versions 1.120.4, 1.121.1, and 1.122.0. Users are strongly advised to upgrade to a patched version, which introduces additional safeguards to restrict expression evaluation. If upgrading is not immediately possible, administrators should consider the following temporary mitigations: Limit workflow creation and editing permissions to fully trusted users only; and/or deploy n8n in a hardened environment with restricted operating system privileges and network access to reduce the impact of potential exploitation. These workarounds do not fully eliminate the risk and should only be used as short-term measures.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
n8nnpm | >= 0.211.0, < 1.120.4 | 1.120.4 |
n8nnpm | >= 1.121.0, < 1.121.1 | 1.121.1 |
Affected products
1Patches
39 files changed · +253 −119
package.json+1 −0 modified@@ -88,6 +88,7 @@ "sqlite3" ], "overrides": { + "ast-types": "0.16.1", "@azure/identity": "^4.3.0", "@lezer/common": "^1.2.0", "@mistralai/mistralai": "^1.10.0",
packages/workflow/package.json+1 −1 modified@@ -52,7 +52,7 @@ "dependencies": { "@n8n/errors": "workspace:^", "@n8n/tournament": "1.0.6", - "ast-types": "0.15.2", + "ast-types": "0.16.1", "callsites": "catalog:", "esprima-next": "5.8.4", "form-data": "catalog:",
packages/workflow/src/expression-evaluator-proxy.ts+6 −2 modified@@ -1,13 +1,17 @@ import { Tournament } from '@n8n/tournament'; -import { DollarSignValidator, PrototypeSanitizer } from './expression-sandboxing'; +import { + DollarSignValidator, + FunctionThisSanitizer, + PrototypeSanitizer, +} from './expression-sandboxing'; type Evaluator = (expr: string, data: unknown) => string | null | (() => unknown); type ErrorHandler = (error: Error) => void; const errorHandler: ErrorHandler = () => {}; const tournamentEvaluator = new Tournament(errorHandler, undefined, undefined, { - before: [], + before: [FunctionThisSanitizer], after: [PrototypeSanitizer, DollarSignValidator], }); const evaluator: Evaluator = tournamentEvaluator.execute.bind(tournamentEvaluator);
packages/workflow/src/expression-sandboxing.ts+68 −1 modified@@ -1,4 +1,4 @@ -import { type ASTAfterHook, astBuilders as b, astVisit } from '@n8n/tournament'; +import { type ASTAfterHook, type ASTBeforeHook, astBuilders as b, astVisit } from '@n8n/tournament'; import { ExpressionError } from './errors'; import { isSafeObjectProperty } from './utils'; @@ -8,6 +8,10 @@ const sanitizerIdentifier = b.identifier(sanitizerName); export const DOLLAR_SIGN_ERROR = 'Cannot access "$" without calling it as a function'; +const EMPTY_CONTEXT = b.objectExpression([ + b.property('init', b.identifier('process'), b.objectExpression([])), +]); + /** * Helper to check if an expression is a valid property access with $ as the property. * Returns true for obj.$ or obj.nested.$ but false for bare $ or other expression contexts. @@ -49,6 +53,69 @@ const isValidDollarPropertyAccess = (expr: unknown): boolean => { return isPropertyDollar && !isObjectDollar && isObjectValid; }; +/** + * Prevents regular functions from binding their `this` to the Node.js global. + */ +export const FunctionThisSanitizer: ASTBeforeHook = (ast, dataNode) => { + astVisit(ast, { + visitCallExpression(path) { + const { node } = path; + + if (node.callee.type !== 'FunctionExpression') { + this.traverse(path); + return; + } + + const fnExpression = node.callee; + + /** + * Called function expressions (IIFEs) - both anonymous and named: + * + * ```js + * (function(x) { return x * 2; })(5) + * (function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); })(5) + * + * // become + * + * (function(x) { return x * 2; }).call({ process: {} }, 5) + * (function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }).call({ process: {} }, 5) + * ``` + */ + this.traverse(path); // depth first to transform inside out + const callExpression = b.callExpression( + b.memberExpression(fnExpression, b.identifier('call')), + [EMPTY_CONTEXT, ...node.arguments], + ); + path.replace(callExpression); + return false; + }, + + visitFunctionExpression(path) { + const { node } = path; + + /** + * Callable function expressions (callbacks) - both anonymous and named: + * + * ```js + * [1, 2, 3].map(function(n) { return n * 2; }) + * [1, 2, 3].map(function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }) + * + * // become + * + * [1, 2, 3].map((function(n) { return n * 2; }).bind({ process: {} })) + * [1, 2, 3].map((function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }).bind({ process: {} })) + * ``` + */ + this.traverse(path); + const boundFunction = b.callExpression(b.memberExpression(node, b.identifier('bind')), [ + EMPTY_CONTEXT, + ]); + path.replace(boundFunction); + return false; + }, + }); +}; + /** * Validates that the $ identifier is only used in allowed contexts. * This prevents user errors like `{{ $ }}` which would return the function object itself.
packages/workflow/src/extensions/expression-extension.ts+1 −1 modified@@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import type { ExpressionKind } from 'ast-types/gen/kinds'; +import type { ExpressionKind } from 'ast-types/lib/gen/kinds'; import type { Config as EsprimaConfig } from 'esprima-next'; import { parse as esprimaParse } from 'esprima-next'; import { DateTime } from 'luxon';
packages/workflow/src/utils.ts+9 −1 modified@@ -332,7 +332,15 @@ export function hasKey<T extends PropertyKey>(value: unknown, key: T): value is return value !== null && typeof value === 'object' && value.hasOwnProperty(key); } -const unsafeObjectProperties = new Set(['__proto__', 'prototype', 'constructor', 'getPrototypeOf']); +const unsafeObjectProperties = new Set([ + '__proto__', + 'prototype', + 'constructor', + 'getPrototypeOf', + 'mainModule', + 'binding', + '_load', +]); /** * Checks if a property key is safe to use on an object, preventing prototype pollution.
packages/workflow/test/expression-sandboxing.test.ts+140 −1 modified@@ -2,6 +2,7 @@ import { Tournament } from '@n8n/tournament'; import { DollarSignValidator, + FunctionThisSanitizer, PrototypeSanitizer, sanitizer, DOLLAR_SIGN_ERROR, @@ -14,7 +15,7 @@ const tournament = new Tournament( undefined, undefined, { - before: [], + before: [FunctionThisSanitizer], after: [PrototypeSanitizer, DollarSignValidator], }, ); @@ -226,3 +227,141 @@ describe('PrototypeSanitizer', () => { }); }); }); + +describe('FunctionThisSanitizer', () => { + describe('call expression where callee is function expression', () => { + it('should transform call expression', () => { + const result = tournament.execute('{{ (function() { return this.process; })() }}', { + __sanitize: sanitizer, + }); + expect(result).toEqual({}); + }); + + it('should handle recursive call expression', () => { + const result = tournament.execute( + '{{ (function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); })(5) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(120); + }); + + it('should not expose process.env through named function', () => { + const result = tournament.execute('{{ (function test(){ return this.process.env })() }}', { + __sanitize: sanitizer, + }); + expect(result).toBe(undefined); + }); + + it('should still allow access to workflow data via variables', () => { + const result = tournament.execute('{{ (function() { return $json.value; })() }}', { + __sanitize: sanitizer, + $json: { value: 'test-value' }, + }); + expect(result).toBe('test-value'); + }); + + it('should handle nested call expression', () => { + const result = tournament.execute( + '{{ (function() { return (function() { return this.process; })(); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual({}); + }); + + it('should handle nested recursive call expression', () => { + const result = tournament.execute( + '{{ (function() { return (function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); })(5); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(120); + }); + }); + + describe('function expression', () => { + it('should transform function expression', () => { + const result = tournament.execute('{{ [1].map(function() { return this.process; }) }}', { + __sanitize: sanitizer, + }); + expect(result).toEqual([{}]); + }); + + it('should handle recursive function expression', () => { + const result = tournament.execute( + '{{ [1, 2, 3, 4, 5].map(function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); }) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual([1, 2, 6, 24, 120]); + }); + + it('should handle nested function expression', () => { + const result = tournament.execute( + '{{ [1, 2, 3].map(function(n) { return function() { return n * 2; }; }).map(function(fn) { return fn(); }) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual([2, 4, 6]); + }); + + it('should handle nested recursion', () => { + const result = tournament.execute( + '{{ (function fibonacci(n) { return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2); })(7) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(13); + }); + }); + + describe('process.env security', () => { + it('should bind function expressions to empty process object', () => { + const processResult = tournament.execute('{{ (function(){ return this.process })() }}', { + __sanitize: sanitizer, + }); + expect(processResult).toEqual({}); + expect(Object.keys(processResult as object)).toEqual([]); + + const envResult = tournament.execute('{{ (function(){ return this.process.env })() }}', { + __sanitize: sanitizer, + }); + expect(envResult).toBe(undefined); + }); + + it('should block process.env in nested functions', () => { + const result = tournament.execute( + '{{ (function outer(){ return (function inner(){ return this.process.env })(); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(undefined); + }); + + it('should block process.env in callbacks', () => { + const result = tournament.execute( + '{{ [1].map(function(){ return this.process.env; })[0] }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(undefined); + }); + + it('should still allow access to workflow variables', () => { + const result = tournament.execute('{{ (function(){ return $json.value })() }}', { + __sanitize: sanitizer, + $json: { value: 'workflow-data' }, + }); + expect(result).toBe('workflow-data'); + }); + }); +});
packages/workflow/test/utils.test.ts+3 −0 modified@@ -379,6 +379,9 @@ describe('isSafeObjectProperty', () => { ['prototype', false], ['constructor', false], ['getPrototypeOf', false], + ['mainModule', false], + ['binding', false], + ['_load', false], ['safeKey', true], ['anotherKey', true], ['toString', true],
pnpm-lock.yaml+24 −112 modified@@ -192,6 +192,7 @@ catalogs: version: 4.5.0 overrides: + ast-types: 0.16.1 '@azure/identity': ^4.3.0 '@lezer/common': ^1.2.0 '@mistralai/mistralai': ^1.10.0 @@ -1062,7 +1063,7 @@ importers: version: 12.1.0 '@getzep/zep-cloud': specifier: 1.0.12 - version: 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d)) + version: 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621)) '@getzep/zep-js': specifier: 0.9.0 version: 0.9.0 @@ -1089,7 +1090,7 @@ importers: version: 0.3.4(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13) '@langchain/community': specifier: 'catalog:' - version: 0.3.50(071f2de44c6bccc3a8cd2fadf2db3e78) + version: 0.3.50(ba725e6da5f3cda58245f84e6fe2ecaf) '@langchain/core': specifier: 'catalog:' version: 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) @@ -1212,7 +1213,7 @@ importers: version: 23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) langchain: specifier: 0.3.33 - version: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) + version: 0.3.33(ca377405f102dc2905a39d54ecb4d621) lodash: specifier: 'catalog:' version: 4.17.21 @@ -3283,8 +3284,8 @@ importers: specifier: 1.0.6 version: 1.0.6 ast-types: - specifier: 0.15.2 - version: 0.15.2 + specifier: 0.16.1 + version: 0.16.1 callsites: specifier: 'catalog:' version: 3.1.0 @@ -4499,28 +4500,24 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [musl] '@biomejs/cli-linux-arm64@1.9.0': resolution: {integrity: sha512-l8U2lcqsl9yKPP5WUdIrKH//C1pWyM2cSUfcTBn6GSvXmsSjBNEdGSdM4Wfne777Oe/9ONaD1Ga53U2HksHHLw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [glibc] '@biomejs/cli-linux-x64-musl@1.9.0': resolution: {integrity: sha512-N3enoFoIrkB6qJWyYfTiYmFdB1R/Mrij1dd1xBHqxxCKZY9GRkEswRX3F1Uqzo5T+9Iu8nAQobDqI/ygicYy/Q==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [musl] '@biomejs/cli-linux-x64@1.9.0': resolution: {integrity: sha512-8jAzjrrJTj510pwq4aVs7ZKkOvEy1D+nzl9DKvrPh4TOyUw5Ie+0EDwXGE2RAkCKHkGNOQBZ78WtIdsATgz5sA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [glibc] '@biomejs/cli-win32-arm64@1.9.0': resolution: {integrity: sha512-AIjwJTGfdWGMRluSQ9pDB29nzce077dfHh0/HMqzztKzgD3spyuo2R9VoaFpbR0hLHPWEH6g6OxxDO7hfkXNkQ==} @@ -5242,79 +5239,67 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -6251,35 +6236,30 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-arm64-musl@0.1.70': resolution: {integrity: sha512-wBTOllEYNfJCHOdZj9v8gLzZ4oY3oyPX8MSRvaxPm/s7RfEXxCyZ8OhJ5xAyicsDdbE5YBZqdmaaeP5+xKxvtg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/canvas-linux-riscv64-gnu@0.1.70': resolution: {integrity: sha512-GVUUPC8TuuFqHip0rxHkUqArQnlzmlXmTEBuXAWdgCv85zTCFH8nOHk/YCF5yo0Z2eOm8nOi90aWs0leJ4OE5Q==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-x64-gnu@0.1.70': resolution: {integrity: sha512-/kvUa2lZRwGNyfznSn5t1ShWJnr/m5acSlhTV3eXECafObjl0VBuA1HJw0QrilLpb4Fe0VLywkpD1NsMoVDROQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-x64-musl@0.1.70': resolution: {integrity: sha512-aqlv8MLpycoMKRmds7JWCfVwNf1fiZxaU7JwJs9/ExjTD8lX2KjsO7CTeAj5Cl4aEuzxUWbJPUUE2Qu9cZ1vfg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/canvas-win32-x64-msvc@0.1.70': resolution: {integrity: sha512-Q9QU3WIpwBTVHk4cPfBjGHGU4U0llQYRXgJtFtYqqGNEOKVN4OT6PQ+ve63xwIPODMpZ0HHyj/KLGc9CWc3EtQ==} @@ -6599,42 +6579,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -6843,56 +6817,48 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.50': resolution: {integrity: sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.42': resolution: {integrity: sha512-/bNTYb9aKNhzdbPn3O4MK2aLv55AlrkUKPE4KNfBYjkoZUfDr4jWp7gsSlvTc5A/99V1RCm9axvt616ZzeXGyA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.50': resolution: {integrity: sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.42': resolution: {integrity: sha512-n/SLa4h342oyeGykZdch7Y3GNCNliRPL4k5wkeZ/5eQZs+c6/ZG1SHCJQoy7bZcmxiMyaXs9HoFmv1PEKrZgWg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.50': resolution: {integrity: sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-beta.42': resolution: {integrity: sha512-4PSd46sFzqpLHSGdaSViAb1mk55sCUMpJg+X8ittXaVocQsV3QLG/uydSH8RyL0ngHX5fy3D70LcCzlB15AgHw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-linux-x64-musl@1.0.0-beta.50': resolution: {integrity: sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-beta.42': resolution: {integrity: sha512-BmWoeJJyeZXmZBcfoxG6J9+rl2G7eO47qdTkAzEegj4n3aC6CBIHOuDcbE8BvhZaEjQR0nh0nJrtEDlt65Q7Sw==} @@ -7040,133 +7006,111 @@ packages: resolution: {integrity: sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-gnueabihf@4.52.4': resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.49.0': resolution: {integrity: sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm-musleabihf@4.52.4': resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.49.0': resolution: {integrity: sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.52.4': resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.49.0': resolution: {integrity: sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-musl@4.52.4': resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.52.4': resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-loongarch64-gnu@4.49.0': resolution: {integrity: sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.49.0': resolution: {integrity: sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.52.4': resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.49.0': resolution: {integrity: sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.52.4': resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.49.0': resolution: {integrity: sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-riscv64-musl@4.52.4': resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.49.0': resolution: {integrity: sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.52.4': resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.49.0': resolution: {integrity: sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.52.4': resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.49.0': resolution: {integrity: sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-linux-x64-musl@4.52.4': resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openharmony-arm64@4.52.4': resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} @@ -8720,49 +8664,41 @@ packages: resolution: {integrity: sha512-UYA0MA8ajkEDCFRQdng/FVx3F6szBvk3EPnkTTQuuO9lV1kPGuTB+V9TmbDxy5ikaEgyWKxa4CI3ySjklZ9lFA==} cpu: [arm64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.9.2': resolution: {integrity: sha512-P/CO3ODU9YJIHFqAkHbquKtFst0COxdphc8TKGL5yCX75GOiVpGqd1d15ahpqu8xXVsqP4MGFP2C3LRZnnL5MA==} cpu: [arm64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.9.2': resolution: {integrity: sha512-uKStFlOELBxBum2s1hODPtgJhY4NxYJE9pAeyBgNEzHgTqTiVBPjfTlPFJkfxyTjQEuxZbbJlJnMCrRgD7ubzw==} cpu: [ppc64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.9.2': resolution: {integrity: sha512-LkbNnZlhINfY9gK30AHs26IIVEZ9PEl9qOScYdmY2o81imJYI4IMnJiW0vJVtXaDHvBvxeAgEy5CflwJFIl3tQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.9.2': resolution: {integrity: sha512-vI+e6FzLyZHSLFNomPi+nT+qUWN4YSj8pFtQZSFTtmgFoxqB6NyjxSjAxEC1m93qn6hUXhIsh8WMp+fGgxCoRg==} cpu: [riscv64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.9.2': resolution: {integrity: sha512-sSO4AlAYhSM2RAzBsRpahcJB1msc6uYLAtP6pesPbZtptF8OU/CbCPhSRW6cnYOGuVmEmWVW5xVboAqCnWTeHQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.9.2': resolution: {integrity: sha512-jkSkwch0uPFva20Mdu8orbQjv2A3G88NExTN2oPTI1AJ+7mZfYW3cDCTyoH6OnctBKbBVeJCEqh0U02lTkqD5w==} cpu: [x64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.9.2': resolution: {integrity: sha512-Uk64NoiTpQbkpl+bXsbeyOPRpUoMdcUqa+hDC1KhMW7aN1lfW8PBlBH4mJ3n3Y47dYE8qi0XTxy1mBACruYBaw==} cpu: [x64] os: [linux] - libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.9.2': resolution: {integrity: sha512-EpBGwkcjDicjR/ybC0g8wO5adPNdVuMrNalVgYcWi+gYtC1XYNuxe3rufcO7dA76OHGeVabcO6cSkPJKVcbCXQ==} @@ -9367,10 +9303,6 @@ packages: resolution: {integrity: sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==} engines: {node: '>=18'} - ast-types@0.15.2: - resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} - engines: {node: '>=4'} - ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -13425,28 +13357,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -17644,8 +17572,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.1.3: - resolution: {integrity: sha512-V1dOD8XYfstOKCnXbWyEJIrhTBMwSyNjv271L1Jlx9ExpNlCSuqOs3OdWrGJ0V544zXufKbcYabi/o+gK8lyfQ==} + vue-component-type-helpers@3.1.4: + resolution: {integrity: sha512-Uws7Ew1OzTTqHW8ZVl/qLl/HB+jf08M0NdFONbVWAx0N4gMLK8yfZDgeB77hDnBmaigWWEn5qP8T9BG59jIeyQ==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -21013,7 +20941,7 @@ snapshots: '@gar/promisify@1.1.3': optional: true - '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d))': + '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621))': dependencies: form-data: 4.0.4 node-fetch: 2.7.0(encoding@0.1.13) @@ -21022,7 +20950,7 @@ snapshots: zod: 3.25.67 optionalDependencies: '@langchain/core': 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) - langchain: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) + langchain: 0.3.33(ca377405f102dc2905a39d54ecb4d621) transitivePeerDependencies: - encoding @@ -21708,7 +21636,7 @@ snapshots: - aws-crt - encoding - '@langchain/community@0.3.50(071f2de44c6bccc3a8cd2fadf2db3e78)': + '@langchain/community@0.3.50(ba725e6da5f3cda58245f84e6fe2ecaf)': dependencies: '@browserbasehq/stagehand': 1.9.0(@playwright/test@1.56.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(encoding@0.1.13)(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))(utf-8-validate@5.0.10)(zod@3.25.67) '@ibm-cloud/watsonx-ai': 1.1.2 @@ -21720,7 +21648,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.3.2 js-yaml: 4.1.0 - langchain: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) + langchain: 0.3.33(ca377405f102dc2905a39d54ecb4d621) langsmith: 0.3.55(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) openai: 5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67) uuid: 10.0.0 @@ -21735,7 +21663,7 @@ snapshots: '@azure/search-documents': 12.1.0 '@azure/storage-blob': 12.26.0 '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) - '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d)) + '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621)) '@getzep/zep-js': 0.9.0 '@google-ai/generativelanguage': 3.4.0(encoding@0.1.13) '@google-cloud/storage': 7.12.1(encoding@0.1.13) @@ -22859,7 +22787,7 @@ snapshots: dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.52.4) estree-walker: 2.0.2 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: rollup: 4.52.4 @@ -24059,7 +23987,7 @@ snapshots: storybook: 9.1.7(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.6.2)(utf-8-validate@5.0.10)(vite@7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.1.3 + vue-component-type-helpers: 3.1.4 '@stylistic/eslint-plugin@5.0.0(eslint@9.29.0(jiti@2.6.1))': dependencies: @@ -25115,15 +25043,15 @@ snapshots: dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: vite: rolldown-vite@7.1.16(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3) '@vitest/mocker@3.2.4(vite@7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: vite: 7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3) @@ -25792,10 +25720,6 @@ snapshots: ast-module-types@6.0.1: {} - ast-types@0.15.2: - dependencies: - tslib: 2.6.2 - ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -25871,14 +25795,6 @@ snapshots: transitivePeerDependencies: - debug - axios@1.12.0(debug@4.4.3): - dependencies: - follow-redirects: 1.15.11(debug@4.4.3) - form-data: 4.0.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - b4a@1.6.7: {} babel-jest@29.6.2(@babel/core@7.28.4): @@ -28655,10 +28571,6 @@ snapshots: optionalDependencies: debug: 4.4.1(supports-color@8.1.1) - follow-redirects@1.15.11(debug@4.4.3): - optionalDependencies: - debug: 4.4.3 - for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -29361,7 +29273,7 @@ snapshots: '@types/debug': 4.1.12 '@types/node': 20.19.21 '@types/tough-cookie': 4.0.5 - axios: 1.12.0(debug@4.4.3) + axios: 1.12.0(debug@4.4.1) camelcase: 6.3.0 debug: 4.4.3 dotenv: 16.6.1 @@ -29371,7 +29283,7 @@ snapshots: isstream: 0.1.2 jsonwebtoken: 9.0.2 mime-types: 2.1.35 - retry-axios: 2.6.0(axios@1.12.0) + retry-axios: 2.6.0(axios@1.12.0(debug@4.4.3)) tough-cookie: 4.1.4 transitivePeerDependencies: - supports-color @@ -30828,7 +30740,7 @@ snapshots: kuler@2.0.0: {} - langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d): + langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621): dependencies: '@langchain/core': 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) '@langchain/openai': 0.6.16(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33480,7 +33392,7 @@ snapshots: recast@0.22.0: dependencies: assert: 2.1.0 - ast-types: 0.15.2 + ast-types: 0.16.1 esprima: 4.0.1 source-map: 0.6.1 tslib: 2.8.1 @@ -33721,7 +33633,7 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 - retry-axios@2.6.0(axios@1.12.0): + retry-axios@2.6.0(axios@1.12.0(debug@4.4.3)): dependencies: axios: 1.12.0(debug@4.4.1) @@ -35386,7 +35298,7 @@ snapshots: obug: 2.0.0(ms@2.1.3) rolldown: 1.0.0-beta.50 rolldown-plugin-dts: 0.17.8(ms@2.1.3)(rolldown@1.0.0-beta.50)(typescript@5.9.2)(vue-tsc@2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2)) - semver: 7.7.3 + semver: 7.7.2 tinyexec: 1.0.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 @@ -36056,7 +35968,7 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.1.3: {} + vue-component-type-helpers@3.1.4: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies:
9 files changed · +253 −30
package.json+1 −0 modified@@ -88,6 +88,7 @@ "sqlite3" ], "overrides": { + "ast-types": "0.16.1", "@azure/identity": "^4.3.0", "@lezer/common": "^1.2.0", "@mistralai/mistralai": "^1.10.0",
packages/workflow/package.json+1 −1 modified@@ -52,7 +52,7 @@ "dependencies": { "@n8n/errors": "workspace:^", "@n8n/tournament": "1.0.6", - "ast-types": "0.15.2", + "ast-types": "0.16.1", "callsites": "catalog:", "esprima-next": "5.8.4", "form-data": "catalog:",
packages/workflow/src/expression-evaluator-proxy.ts+6 −2 modified@@ -1,13 +1,17 @@ import { Tournament } from '@n8n/tournament'; -import { DollarSignValidator, PrototypeSanitizer } from './expression-sandboxing'; +import { + DollarSignValidator, + FunctionThisSanitizer, + PrototypeSanitizer, +} from './expression-sandboxing'; type Evaluator = (expr: string, data: unknown) => string | null | (() => unknown); type ErrorHandler = (error: Error) => void; const errorHandler: ErrorHandler = () => {}; const tournamentEvaluator = new Tournament(errorHandler, undefined, undefined, { - before: [], + before: [FunctionThisSanitizer], after: [PrototypeSanitizer, DollarSignValidator], }); const evaluator: Evaluator = tournamentEvaluator.execute.bind(tournamentEvaluator);
packages/workflow/src/expression-sandboxing.ts+68 −1 modified@@ -1,4 +1,4 @@ -import { type ASTAfterHook, astBuilders as b, astVisit } from '@n8n/tournament'; +import { type ASTAfterHook, type ASTBeforeHook, astBuilders as b, astVisit } from '@n8n/tournament'; import { ExpressionError } from './errors'; import { isSafeObjectProperty } from './utils'; @@ -8,6 +8,10 @@ const sanitizerIdentifier = b.identifier(sanitizerName); export const DOLLAR_SIGN_ERROR = 'Cannot access "$" without calling it as a function'; +const EMPTY_CONTEXT = b.objectExpression([ + b.property('init', b.identifier('process'), b.objectExpression([])), +]); + /** * Helper to check if an expression is a valid property access with $ as the property. * Returns true for obj.$ or obj.nested.$ but false for bare $ or other expression contexts. @@ -49,6 +53,69 @@ const isValidDollarPropertyAccess = (expr: unknown): boolean => { return isPropertyDollar && !isObjectDollar && isObjectValid; }; +/** + * Prevents regular functions from binding their `this` to the Node.js global. + */ +export const FunctionThisSanitizer: ASTBeforeHook = (ast, dataNode) => { + astVisit(ast, { + visitCallExpression(path) { + const { node } = path; + + if (node.callee.type !== 'FunctionExpression') { + this.traverse(path); + return; + } + + const fnExpression = node.callee; + + /** + * Called function expressions (IIFEs) - both anonymous and named: + * + * ```js + * (function(x) { return x * 2; })(5) + * (function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); })(5) + * + * // become + * + * (function(x) { return x * 2; }).call({ process: {} }, 5) + * (function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }).call({ process: {} }, 5) + * ``` + */ + this.traverse(path); // depth first to transform inside out + const callExpression = b.callExpression( + b.memberExpression(fnExpression, b.identifier('call')), + [EMPTY_CONTEXT, ...node.arguments], + ); + path.replace(callExpression); + return false; + }, + + visitFunctionExpression(path) { + const { node } = path; + + /** + * Callable function expressions (callbacks) - both anonymous and named: + * + * ```js + * [1, 2, 3].map(function(n) { return n * 2; }) + * [1, 2, 3].map(function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }) + * + * // become + * + * [1, 2, 3].map((function(n) { return n * 2; }).bind({ process: {} })) + * [1, 2, 3].map((function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }).bind({ process: {} })) + * ``` + */ + this.traverse(path); + const boundFunction = b.callExpression(b.memberExpression(node, b.identifier('bind')), [ + EMPTY_CONTEXT, + ]); + path.replace(boundFunction); + return false; + }, + }); +}; + /** * Validates that the $ identifier is only used in allowed contexts. * This prevents user errors like `{{ $ }}` which would return the function object itself.
packages/workflow/src/extensions/expression-extension.ts+1 −1 modified@@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import type { ExpressionKind } from 'ast-types/gen/kinds'; +import type { ExpressionKind } from 'ast-types/lib/gen/kinds'; import type { Config as EsprimaConfig } from 'esprima-next'; import { parse as esprimaParse } from 'esprima-next'; import { DateTime } from 'luxon';
packages/workflow/src/utils.ts+9 −1 modified@@ -332,7 +332,15 @@ export function hasKey<T extends PropertyKey>(value: unknown, key: T): value is return value !== null && typeof value === 'object' && value.hasOwnProperty(key); } -const unsafeObjectProperties = new Set(['__proto__', 'prototype', 'constructor', 'getPrototypeOf']); +const unsafeObjectProperties = new Set([ + '__proto__', + 'prototype', + 'constructor', + 'getPrototypeOf', + 'mainModule', + 'binding', + '_load', +]); /** * Checks if a property key is safe to use on an object, preventing prototype pollution.
packages/workflow/test/expression-sandboxing.test.ts+140 −1 modified@@ -2,6 +2,7 @@ import { Tournament } from '@n8n/tournament'; import { DollarSignValidator, + FunctionThisSanitizer, PrototypeSanitizer, sanitizer, DOLLAR_SIGN_ERROR, @@ -14,7 +15,7 @@ const tournament = new Tournament( undefined, undefined, { - before: [], + before: [FunctionThisSanitizer], after: [PrototypeSanitizer, DollarSignValidator], }, ); @@ -226,3 +227,141 @@ describe('PrototypeSanitizer', () => { }); }); }); + +describe('FunctionThisSanitizer', () => { + describe('call expression where callee is function expression', () => { + it('should transform call expression', () => { + const result = tournament.execute('{{ (function() { return this.process; })() }}', { + __sanitize: sanitizer, + }); + expect(result).toEqual({}); + }); + + it('should handle recursive call expression', () => { + const result = tournament.execute( + '{{ (function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); })(5) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(120); + }); + + it('should not expose process.env through named function', () => { + const result = tournament.execute('{{ (function test(){ return this.process.env })() }}', { + __sanitize: sanitizer, + }); + expect(result).toBe(undefined); + }); + + it('should still allow access to workflow data via variables', () => { + const result = tournament.execute('{{ (function() { return $json.value; })() }}', { + __sanitize: sanitizer, + $json: { value: 'test-value' }, + }); + expect(result).toBe('test-value'); + }); + + it('should handle nested call expression', () => { + const result = tournament.execute( + '{{ (function() { return (function() { return this.process; })(); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual({}); + }); + + it('should handle nested recursive call expression', () => { + const result = tournament.execute( + '{{ (function() { return (function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); })(5); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(120); + }); + }); + + describe('function expression', () => { + it('should transform function expression', () => { + const result = tournament.execute('{{ [1].map(function() { return this.process; }) }}', { + __sanitize: sanitizer, + }); + expect(result).toEqual([{}]); + }); + + it('should handle recursive function expression', () => { + const result = tournament.execute( + '{{ [1, 2, 3, 4, 5].map(function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); }) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual([1, 2, 6, 24, 120]); + }); + + it('should handle nested function expression', () => { + const result = tournament.execute( + '{{ [1, 2, 3].map(function(n) { return function() { return n * 2; }; }).map(function(fn) { return fn(); }) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual([2, 4, 6]); + }); + + it('should handle nested recursion', () => { + const result = tournament.execute( + '{{ (function fibonacci(n) { return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2); })(7) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(13); + }); + }); + + describe('process.env security', () => { + it('should bind function expressions to empty process object', () => { + const processResult = tournament.execute('{{ (function(){ return this.process })() }}', { + __sanitize: sanitizer, + }); + expect(processResult).toEqual({}); + expect(Object.keys(processResult as object)).toEqual([]); + + const envResult = tournament.execute('{{ (function(){ return this.process.env })() }}', { + __sanitize: sanitizer, + }); + expect(envResult).toBe(undefined); + }); + + it('should block process.env in nested functions', () => { + const result = tournament.execute( + '{{ (function outer(){ return (function inner(){ return this.process.env })(); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(undefined); + }); + + it('should block process.env in callbacks', () => { + const result = tournament.execute( + '{{ [1].map(function(){ return this.process.env; })[0] }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(undefined); + }); + + it('should still allow access to workflow variables', () => { + const result = tournament.execute('{{ (function(){ return $json.value })() }}', { + __sanitize: sanitizer, + $json: { value: 'workflow-data' }, + }); + expect(result).toBe('workflow-data'); + }); + }); +});
packages/workflow/test/utils.test.ts+3 −0 modified@@ -379,6 +379,9 @@ describe('isSafeObjectProperty', () => { ['prototype', false], ['constructor', false], ['getPrototypeOf', false], + ['mainModule', false], + ['binding', false], + ['_load', false], ['safeKey', true], ['anotherKey', true], ['toString', true],
pnpm-lock.yaml+24 −23 modified@@ -186,6 +186,7 @@ catalogs: version: 4.5.0 overrides: + ast-types: 0.16.1 '@azure/identity': ^4.3.0 '@lezer/common': ^1.2.0 '@mistralai/mistralai': ^1.10.0 @@ -3267,8 +3268,8 @@ importers: specifier: 1.0.6 version: 1.0.6 ast-types: - specifier: 0.15.2 - version: 0.15.2 + specifier: 0.16.1 + version: 0.16.1 callsites: specifier: 'catalog:' version: 3.1.0 @@ -9340,10 +9341,6 @@ packages: resolution: {integrity: sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==} engines: {node: '>=18'} - ast-types@0.15.2: - resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} - engines: {node: '>=4'} - ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -17595,8 +17592,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.1.3: - resolution: {integrity: sha512-V1dOD8XYfstOKCnXbWyEJIrhTBMwSyNjv271L1Jlx9ExpNlCSuqOs3OdWrGJ0V544zXufKbcYabi/o+gK8lyfQ==} + vue-component-type-helpers@3.1.4: + resolution: {integrity: sha512-Uws7Ew1OzTTqHW8ZVl/qLl/HB+jf08M0NdFONbVWAx0N4gMLK8yfZDgeB77hDnBmaigWWEn5qP8T9BG59jIeyQ==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -22948,7 +22945,7 @@ snapshots: '@rudderstack/rudder-sdk-node@2.1.4(tslib@2.8.1)': dependencies: - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 axios-retry: 4.5.0(axios@1.12.0) component-type: 2.0.0 join-component: 1.1.0 @@ -24006,7 +24003,7 @@ snapshots: storybook: 9.1.7(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.6.2)(utf-8-validate@5.0.10)(vite@7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.1.3 + vue-component-type-helpers: 3.1.4 '@stylistic/eslint-plugin@5.0.0(eslint@9.29.0(jiti@2.6.1))': dependencies: @@ -25739,10 +25736,6 @@ snapshots: ast-module-types@6.0.1: {} - ast-types@0.15.2: - dependencies: - tslib: 2.6.2 - ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -25799,9 +25792,17 @@ snapshots: axios-retry@4.5.0(axios@1.12.0): dependencies: - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 is-retry-allowed: 2.2.0 + axios@1.12.0: + dependencies: + follow-redirects: 1.15.11(debug@4.4.1) + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axios@1.12.0(debug@4.3.6): dependencies: follow-redirects: 1.15.11(debug@4.3.6) @@ -26206,7 +26207,7 @@ snapshots: bundlemon@3.1.0(typescript@5.9.2): dependencies: - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 axios-retry: 4.5.0(axios@1.12.0) brotli-size: 4.0.0 bundlemon-utils: 2.0.1 @@ -29416,7 +29417,7 @@ snapshots: infisical-node@1.3.0: dependencies: - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 dotenv: 16.3.1 tweetnacl: 1.0.3 tweetnacl-util: 0.15.1 @@ -30817,7 +30818,7 @@ snapshots: '@langchain/groq': 0.2.3(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13) '@langchain/mistralai': 0.2.3(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))) '@langchain/ollama': 0.2.3(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))) - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 cheerio: 1.0.0 handlebars: 4.7.8 transitivePeerDependencies: @@ -32963,7 +32964,7 @@ snapshots: posthog-node@3.2.1: dependencies: - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 rusha: 0.8.14 transitivePeerDependencies: - debug @@ -33440,7 +33441,7 @@ snapshots: recast@0.22.0: dependencies: assert: 2.1.0 - ast-types: 0.15.2 + ast-types: 0.16.1 esprima: 4.0.1 source-map: 0.6.1 tslib: 2.8.1 @@ -33683,7 +33684,7 @@ snapshots: retry-axios@2.6.0(axios@1.12.0): dependencies: - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 retry-request@7.0.2(encoding@0.1.13): dependencies: @@ -34290,7 +34291,7 @@ snapshots: asn1.js: 5.4.1 asn1.js-rfc2560: 5.0.1(asn1.js@5.4.1) asn1.js-rfc5280: 3.0.0 - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0 big-integer: 1.6.52 bignumber.js: 9.1.2 binascii: 0.0.2 @@ -36011,7 +36012,7 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.1.3: {} + vue-component-type-helpers@3.1.4: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies:
9 files changed · +253 −119
package.json+1 −0 modified@@ -88,6 +88,7 @@ "sqlite3" ], "overrides": { + "ast-types": "0.16.1", "@azure/identity": "^4.3.0", "@lezer/common": "^1.2.0", "@mistralai/mistralai": "^1.10.0",
packages/workflow/package.json+1 −1 modified@@ -52,7 +52,7 @@ "dependencies": { "@n8n/errors": "workspace:^", "@n8n/tournament": "1.0.6", - "ast-types": "0.15.2", + "ast-types": "0.16.1", "callsites": "catalog:", "esprima-next": "5.8.4", "form-data": "catalog:",
packages/workflow/src/expression-evaluator-proxy.ts+6 −2 modified@@ -1,13 +1,17 @@ import { Tournament } from '@n8n/tournament'; -import { DollarSignValidator, PrototypeSanitizer } from './expression-sandboxing'; +import { + DollarSignValidator, + FunctionThisSanitizer, + PrototypeSanitizer, +} from './expression-sandboxing'; type Evaluator = (expr: string, data: unknown) => string | null | (() => unknown); type ErrorHandler = (error: Error) => void; const errorHandler: ErrorHandler = () => {}; const tournamentEvaluator = new Tournament(errorHandler, undefined, undefined, { - before: [], + before: [FunctionThisSanitizer], after: [PrototypeSanitizer, DollarSignValidator], }); const evaluator: Evaluator = tournamentEvaluator.execute.bind(tournamentEvaluator);
packages/workflow/src/expression-sandboxing.ts+68 −1 modified@@ -1,4 +1,4 @@ -import { type ASTAfterHook, astBuilders as b, astVisit } from '@n8n/tournament'; +import { type ASTAfterHook, type ASTBeforeHook, astBuilders as b, astVisit } from '@n8n/tournament'; import { ExpressionError } from './errors'; import { isSafeObjectProperty } from './utils'; @@ -8,6 +8,10 @@ const sanitizerIdentifier = b.identifier(sanitizerName); export const DOLLAR_SIGN_ERROR = 'Cannot access "$" without calling it as a function'; +const EMPTY_CONTEXT = b.objectExpression([ + b.property('init', b.identifier('process'), b.objectExpression([])), +]); + /** * Helper to check if an expression is a valid property access with $ as the property. * Returns true for obj.$ or obj.nested.$ but false for bare $ or other expression contexts. @@ -49,6 +53,69 @@ const isValidDollarPropertyAccess = (expr: unknown): boolean => { return isPropertyDollar && !isObjectDollar && isObjectValid; }; +/** + * Prevents regular functions from binding their `this` to the Node.js global. + */ +export const FunctionThisSanitizer: ASTBeforeHook = (ast, dataNode) => { + astVisit(ast, { + visitCallExpression(path) { + const { node } = path; + + if (node.callee.type !== 'FunctionExpression') { + this.traverse(path); + return; + } + + const fnExpression = node.callee; + + /** + * Called function expressions (IIFEs) - both anonymous and named: + * + * ```js + * (function(x) { return x * 2; })(5) + * (function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); })(5) + * + * // become + * + * (function(x) { return x * 2; }).call({ process: {} }, 5) + * (function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }).call({ process: {} }, 5) + * ``` + */ + this.traverse(path); // depth first to transform inside out + const callExpression = b.callExpression( + b.memberExpression(fnExpression, b.identifier('call')), + [EMPTY_CONTEXT, ...node.arguments], + ); + path.replace(callExpression); + return false; + }, + + visitFunctionExpression(path) { + const { node } = path; + + /** + * Callable function expressions (callbacks) - both anonymous and named: + * + * ```js + * [1, 2, 3].map(function(n) { return n * 2; }) + * [1, 2, 3].map(function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }) + * + * // become + * + * [1, 2, 3].map((function(n) { return n * 2; }).bind({ process: {} })) + * [1, 2, 3].map((function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }).bind({ process: {} })) + * ``` + */ + this.traverse(path); + const boundFunction = b.callExpression(b.memberExpression(node, b.identifier('bind')), [ + EMPTY_CONTEXT, + ]); + path.replace(boundFunction); + return false; + }, + }); +}; + /** * Validates that the $ identifier is only used in allowed contexts. * This prevents user errors like `{{ $ }}` which would return the function object itself.
packages/workflow/src/extensions/expression-extension.ts+1 −1 modified@@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import type { ExpressionKind } from 'ast-types/gen/kinds'; +import type { ExpressionKind } from 'ast-types/lib/gen/kinds'; import type { Config as EsprimaConfig } from 'esprima-next'; import { parse as esprimaParse } from 'esprima-next'; import { DateTime } from 'luxon';
packages/workflow/src/utils.ts+9 −1 modified@@ -332,7 +332,15 @@ export function hasKey<T extends PropertyKey>(value: unknown, key: T): value is return value !== null && typeof value === 'object' && value.hasOwnProperty(key); } -const unsafeObjectProperties = new Set(['__proto__', 'prototype', 'constructor', 'getPrototypeOf']); +const unsafeObjectProperties = new Set([ + '__proto__', + 'prototype', + 'constructor', + 'getPrototypeOf', + 'mainModule', + 'binding', + '_load', +]); /** * Checks if a property key is safe to use on an object, preventing prototype pollution.
packages/workflow/test/expression-sandboxing.test.ts+140 −1 modified@@ -2,6 +2,7 @@ import { Tournament } from '@n8n/tournament'; import { DollarSignValidator, + FunctionThisSanitizer, PrototypeSanitizer, sanitizer, DOLLAR_SIGN_ERROR, @@ -14,7 +15,7 @@ const tournament = new Tournament( undefined, undefined, { - before: [], + before: [FunctionThisSanitizer], after: [PrototypeSanitizer, DollarSignValidator], }, ); @@ -226,3 +227,141 @@ describe('PrototypeSanitizer', () => { }); }); }); + +describe('FunctionThisSanitizer', () => { + describe('call expression where callee is function expression', () => { + it('should transform call expression', () => { + const result = tournament.execute('{{ (function() { return this.process; })() }}', { + __sanitize: sanitizer, + }); + expect(result).toEqual({}); + }); + + it('should handle recursive call expression', () => { + const result = tournament.execute( + '{{ (function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); })(5) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(120); + }); + + it('should not expose process.env through named function', () => { + const result = tournament.execute('{{ (function test(){ return this.process.env })() }}', { + __sanitize: sanitizer, + }); + expect(result).toBe(undefined); + }); + + it('should still allow access to workflow data via variables', () => { + const result = tournament.execute('{{ (function() { return $json.value; })() }}', { + __sanitize: sanitizer, + $json: { value: 'test-value' }, + }); + expect(result).toBe('test-value'); + }); + + it('should handle nested call expression', () => { + const result = tournament.execute( + '{{ (function() { return (function() { return this.process; })(); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual({}); + }); + + it('should handle nested recursive call expression', () => { + const result = tournament.execute( + '{{ (function() { return (function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); })(5); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(120); + }); + }); + + describe('function expression', () => { + it('should transform function expression', () => { + const result = tournament.execute('{{ [1].map(function() { return this.process; }) }}', { + __sanitize: sanitizer, + }); + expect(result).toEqual([{}]); + }); + + it('should handle recursive function expression', () => { + const result = tournament.execute( + '{{ [1, 2, 3, 4, 5].map(function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); }) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual([1, 2, 6, 24, 120]); + }); + + it('should handle nested function expression', () => { + const result = tournament.execute( + '{{ [1, 2, 3].map(function(n) { return function() { return n * 2; }; }).map(function(fn) { return fn(); }) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toEqual([2, 4, 6]); + }); + + it('should handle nested recursion', () => { + const result = tournament.execute( + '{{ (function fibonacci(n) { return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2); })(7) }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(13); + }); + }); + + describe('process.env security', () => { + it('should bind function expressions to empty process object', () => { + const processResult = tournament.execute('{{ (function(){ return this.process })() }}', { + __sanitize: sanitizer, + }); + expect(processResult).toEqual({}); + expect(Object.keys(processResult as object)).toEqual([]); + + const envResult = tournament.execute('{{ (function(){ return this.process.env })() }}', { + __sanitize: sanitizer, + }); + expect(envResult).toBe(undefined); + }); + + it('should block process.env in nested functions', () => { + const result = tournament.execute( + '{{ (function outer(){ return (function inner(){ return this.process.env })(); })() }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(undefined); + }); + + it('should block process.env in callbacks', () => { + const result = tournament.execute( + '{{ [1].map(function(){ return this.process.env; })[0] }}', + { + __sanitize: sanitizer, + }, + ); + expect(result).toBe(undefined); + }); + + it('should still allow access to workflow variables', () => { + const result = tournament.execute('{{ (function(){ return $json.value })() }}', { + __sanitize: sanitizer, + $json: { value: 'workflow-data' }, + }); + expect(result).toBe('workflow-data'); + }); + }); +});
packages/workflow/test/utils.test.ts+3 −0 modified@@ -379,6 +379,9 @@ describe('isSafeObjectProperty', () => { ['prototype', false], ['constructor', false], ['getPrototypeOf', false], + ['mainModule', false], + ['binding', false], + ['_load', false], ['safeKey', true], ['anotherKey', true], ['toString', true],
pnpm-lock.yaml+24 −112 modified@@ -192,6 +192,7 @@ catalogs: version: 4.5.0 overrides: + ast-types: 0.16.1 '@azure/identity': ^4.3.0 '@lezer/common': ^1.2.0 '@mistralai/mistralai': ^1.10.0 @@ -1062,7 +1063,7 @@ importers: version: 12.1.0 '@getzep/zep-cloud': specifier: 1.0.12 - version: 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d)) + version: 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621)) '@getzep/zep-js': specifier: 0.9.0 version: 0.9.0 @@ -1089,7 +1090,7 @@ importers: version: 0.3.4(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13) '@langchain/community': specifier: 'catalog:' - version: 0.3.50(071f2de44c6bccc3a8cd2fadf2db3e78) + version: 0.3.50(ba725e6da5f3cda58245f84e6fe2ecaf) '@langchain/core': specifier: 'catalog:' version: 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) @@ -1212,7 +1213,7 @@ importers: version: 23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) langchain: specifier: 0.3.33 - version: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) + version: 0.3.33(ca377405f102dc2905a39d54ecb4d621) lodash: specifier: 'catalog:' version: 4.17.21 @@ -3283,8 +3284,8 @@ importers: specifier: 1.0.6 version: 1.0.6 ast-types: - specifier: 0.15.2 - version: 0.15.2 + specifier: 0.16.1 + version: 0.16.1 callsites: specifier: 'catalog:' version: 3.1.0 @@ -4499,28 +4500,24 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [musl] '@biomejs/cli-linux-arm64@1.9.0': resolution: {integrity: sha512-l8U2lcqsl9yKPP5WUdIrKH//C1pWyM2cSUfcTBn6GSvXmsSjBNEdGSdM4Wfne777Oe/9ONaD1Ga53U2HksHHLw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [glibc] '@biomejs/cli-linux-x64-musl@1.9.0': resolution: {integrity: sha512-N3enoFoIrkB6qJWyYfTiYmFdB1R/Mrij1dd1xBHqxxCKZY9GRkEswRX3F1Uqzo5T+9Iu8nAQobDqI/ygicYy/Q==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [musl] '@biomejs/cli-linux-x64@1.9.0': resolution: {integrity: sha512-8jAzjrrJTj510pwq4aVs7ZKkOvEy1D+nzl9DKvrPh4TOyUw5Ie+0EDwXGE2RAkCKHkGNOQBZ78WtIdsATgz5sA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [glibc] '@biomejs/cli-win32-arm64@1.9.0': resolution: {integrity: sha512-AIjwJTGfdWGMRluSQ9pDB29nzce077dfHh0/HMqzztKzgD3spyuo2R9VoaFpbR0hLHPWEH6g6OxxDO7hfkXNkQ==} @@ -5242,79 +5239,67 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -6251,35 +6236,30 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-arm64-musl@0.1.70': resolution: {integrity: sha512-wBTOllEYNfJCHOdZj9v8gLzZ4oY3oyPX8MSRvaxPm/s7RfEXxCyZ8OhJ5xAyicsDdbE5YBZqdmaaeP5+xKxvtg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/canvas-linux-riscv64-gnu@0.1.70': resolution: {integrity: sha512-GVUUPC8TuuFqHip0rxHkUqArQnlzmlXmTEBuXAWdgCv85zTCFH8nOHk/YCF5yo0Z2eOm8nOi90aWs0leJ4OE5Q==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-x64-gnu@0.1.70': resolution: {integrity: sha512-/kvUa2lZRwGNyfznSn5t1ShWJnr/m5acSlhTV3eXECafObjl0VBuA1HJw0QrilLpb4Fe0VLywkpD1NsMoVDROQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-x64-musl@0.1.70': resolution: {integrity: sha512-aqlv8MLpycoMKRmds7JWCfVwNf1fiZxaU7JwJs9/ExjTD8lX2KjsO7CTeAj5Cl4aEuzxUWbJPUUE2Qu9cZ1vfg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/canvas-win32-x64-msvc@0.1.70': resolution: {integrity: sha512-Q9QU3WIpwBTVHk4cPfBjGHGU4U0llQYRXgJtFtYqqGNEOKVN4OT6PQ+ve63xwIPODMpZ0HHyj/KLGc9CWc3EtQ==} @@ -6599,42 +6579,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -6843,56 +6817,48 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.50': resolution: {integrity: sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.42': resolution: {integrity: sha512-/bNTYb9aKNhzdbPn3O4MK2aLv55AlrkUKPE4KNfBYjkoZUfDr4jWp7gsSlvTc5A/99V1RCm9axvt616ZzeXGyA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.50': resolution: {integrity: sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.42': resolution: {integrity: sha512-n/SLa4h342oyeGykZdch7Y3GNCNliRPL4k5wkeZ/5eQZs+c6/ZG1SHCJQoy7bZcmxiMyaXs9HoFmv1PEKrZgWg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.50': resolution: {integrity: sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-beta.42': resolution: {integrity: sha512-4PSd46sFzqpLHSGdaSViAb1mk55sCUMpJg+X8ittXaVocQsV3QLG/uydSH8RyL0ngHX5fy3D70LcCzlB15AgHw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-linux-x64-musl@1.0.0-beta.50': resolution: {integrity: sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-beta.42': resolution: {integrity: sha512-BmWoeJJyeZXmZBcfoxG6J9+rl2G7eO47qdTkAzEegj4n3aC6CBIHOuDcbE8BvhZaEjQR0nh0nJrtEDlt65Q7Sw==} @@ -7040,133 +7006,111 @@ packages: resolution: {integrity: sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-gnueabihf@4.52.4': resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.49.0': resolution: {integrity: sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm-musleabihf@4.52.4': resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.49.0': resolution: {integrity: sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.52.4': resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.49.0': resolution: {integrity: sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-musl@4.52.4': resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.52.4': resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-loongarch64-gnu@4.49.0': resolution: {integrity: sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.49.0': resolution: {integrity: sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.52.4': resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.49.0': resolution: {integrity: sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.52.4': resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.49.0': resolution: {integrity: sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-riscv64-musl@4.52.4': resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.49.0': resolution: {integrity: sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.52.4': resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.49.0': resolution: {integrity: sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.52.4': resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.49.0': resolution: {integrity: sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-linux-x64-musl@4.52.4': resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openharmony-arm64@4.52.4': resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} @@ -8720,49 +8664,41 @@ packages: resolution: {integrity: sha512-UYA0MA8ajkEDCFRQdng/FVx3F6szBvk3EPnkTTQuuO9lV1kPGuTB+V9TmbDxy5ikaEgyWKxa4CI3ySjklZ9lFA==} cpu: [arm64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.9.2': resolution: {integrity: sha512-P/CO3ODU9YJIHFqAkHbquKtFst0COxdphc8TKGL5yCX75GOiVpGqd1d15ahpqu8xXVsqP4MGFP2C3LRZnnL5MA==} cpu: [arm64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.9.2': resolution: {integrity: sha512-uKStFlOELBxBum2s1hODPtgJhY4NxYJE9pAeyBgNEzHgTqTiVBPjfTlPFJkfxyTjQEuxZbbJlJnMCrRgD7ubzw==} cpu: [ppc64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.9.2': resolution: {integrity: sha512-LkbNnZlhINfY9gK30AHs26IIVEZ9PEl9qOScYdmY2o81imJYI4IMnJiW0vJVtXaDHvBvxeAgEy5CflwJFIl3tQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.9.2': resolution: {integrity: sha512-vI+e6FzLyZHSLFNomPi+nT+qUWN4YSj8pFtQZSFTtmgFoxqB6NyjxSjAxEC1m93qn6hUXhIsh8WMp+fGgxCoRg==} cpu: [riscv64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.9.2': resolution: {integrity: sha512-sSO4AlAYhSM2RAzBsRpahcJB1msc6uYLAtP6pesPbZtptF8OU/CbCPhSRW6cnYOGuVmEmWVW5xVboAqCnWTeHQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.9.2': resolution: {integrity: sha512-jkSkwch0uPFva20Mdu8orbQjv2A3G88NExTN2oPTI1AJ+7mZfYW3cDCTyoH6OnctBKbBVeJCEqh0U02lTkqD5w==} cpu: [x64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.9.2': resolution: {integrity: sha512-Uk64NoiTpQbkpl+bXsbeyOPRpUoMdcUqa+hDC1KhMW7aN1lfW8PBlBH4mJ3n3Y47dYE8qi0XTxy1mBACruYBaw==} cpu: [x64] os: [linux] - libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.9.2': resolution: {integrity: sha512-EpBGwkcjDicjR/ybC0g8wO5adPNdVuMrNalVgYcWi+gYtC1XYNuxe3rufcO7dA76OHGeVabcO6cSkPJKVcbCXQ==} @@ -9367,10 +9303,6 @@ packages: resolution: {integrity: sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==} engines: {node: '>=18'} - ast-types@0.15.2: - resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} - engines: {node: '>=4'} - ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -13425,28 +13357,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -17644,8 +17572,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.1.3: - resolution: {integrity: sha512-V1dOD8XYfstOKCnXbWyEJIrhTBMwSyNjv271L1Jlx9ExpNlCSuqOs3OdWrGJ0V544zXufKbcYabi/o+gK8lyfQ==} + vue-component-type-helpers@3.1.4: + resolution: {integrity: sha512-Uws7Ew1OzTTqHW8ZVl/qLl/HB+jf08M0NdFONbVWAx0N4gMLK8yfZDgeB77hDnBmaigWWEn5qP8T9BG59jIeyQ==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -21013,7 +20941,7 @@ snapshots: '@gar/promisify@1.1.3': optional: true - '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d))': + '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621))': dependencies: form-data: 4.0.4 node-fetch: 2.7.0(encoding@0.1.13) @@ -21022,7 +20950,7 @@ snapshots: zod: 3.25.67 optionalDependencies: '@langchain/core': 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) - langchain: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) + langchain: 0.3.33(ca377405f102dc2905a39d54ecb4d621) transitivePeerDependencies: - encoding @@ -21708,7 +21636,7 @@ snapshots: - aws-crt - encoding - '@langchain/community@0.3.50(071f2de44c6bccc3a8cd2fadf2db3e78)': + '@langchain/community@0.3.50(ba725e6da5f3cda58245f84e6fe2ecaf)': dependencies: '@browserbasehq/stagehand': 1.9.0(@playwright/test@1.56.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(encoding@0.1.13)(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))(utf-8-validate@5.0.10)(zod@3.25.67) '@ibm-cloud/watsonx-ai': 1.1.2 @@ -21720,7 +21648,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.3.2 js-yaml: 4.1.0 - langchain: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) + langchain: 0.3.33(ca377405f102dc2905a39d54ecb4d621) langsmith: 0.3.55(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) openai: 5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67) uuid: 10.0.0 @@ -21735,7 +21663,7 @@ snapshots: '@azure/search-documents': 12.1.0 '@azure/storage-blob': 12.26.0 '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) - '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d)) + '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621)) '@getzep/zep-js': 0.9.0 '@google-ai/generativelanguage': 3.4.0(encoding@0.1.13) '@google-cloud/storage': 7.12.1(encoding@0.1.13) @@ -22859,7 +22787,7 @@ snapshots: dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.52.4) estree-walker: 2.0.2 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: rollup: 4.52.4 @@ -24059,7 +23987,7 @@ snapshots: storybook: 9.1.7(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.6.2)(utf-8-validate@5.0.10)(vite@7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.1.3 + vue-component-type-helpers: 3.1.4 '@stylistic/eslint-plugin@5.0.0(eslint@9.29.0(jiti@2.6.1))': dependencies: @@ -25115,15 +25043,15 @@ snapshots: dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: vite: rolldown-vite@7.1.16(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3) '@vitest/mocker@3.2.4(vite@7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: vite: 7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3) @@ -25792,10 +25720,6 @@ snapshots: ast-module-types@6.0.1: {} - ast-types@0.15.2: - dependencies: - tslib: 2.6.2 - ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -25871,14 +25795,6 @@ snapshots: transitivePeerDependencies: - debug - axios@1.12.0(debug@4.4.3): - dependencies: - follow-redirects: 1.15.11(debug@4.4.3) - form-data: 4.0.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - b4a@1.6.7: {} babel-jest@29.6.2(@babel/core@7.28.4): @@ -28655,10 +28571,6 @@ snapshots: optionalDependencies: debug: 4.4.1(supports-color@8.1.1) - follow-redirects@1.15.11(debug@4.4.3): - optionalDependencies: - debug: 4.4.3 - for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -29361,7 +29273,7 @@ snapshots: '@types/debug': 4.1.12 '@types/node': 20.19.21 '@types/tough-cookie': 4.0.5 - axios: 1.12.0(debug@4.4.3) + axios: 1.12.0(debug@4.4.1) camelcase: 6.3.0 debug: 4.4.3 dotenv: 16.6.1 @@ -29371,7 +29283,7 @@ snapshots: isstream: 0.1.2 jsonwebtoken: 9.0.2 mime-types: 2.1.35 - retry-axios: 2.6.0(axios@1.12.0) + retry-axios: 2.6.0(axios@1.12.0(debug@4.4.3)) tough-cookie: 4.1.4 transitivePeerDependencies: - supports-color @@ -30828,7 +30740,7 @@ snapshots: kuler@2.0.0: {} - langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d): + langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621): dependencies: '@langchain/core': 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) '@langchain/openai': 0.6.16(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33480,7 +33392,7 @@ snapshots: recast@0.22.0: dependencies: assert: 2.1.0 - ast-types: 0.15.2 + ast-types: 0.16.1 esprima: 4.0.1 source-map: 0.6.1 tslib: 2.8.1 @@ -33721,7 +33633,7 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 - retry-axios@2.6.0(axios@1.12.0): + retry-axios@2.6.0(axios@1.12.0(debug@4.4.3)): dependencies: axios: 1.12.0(debug@4.4.1) @@ -35386,7 +35298,7 @@ snapshots: obug: 2.0.0(ms@2.1.3) rolldown: 1.0.0-beta.50 rolldown-plugin-dts: 0.17.8(ms@2.1.3)(rolldown@1.0.0-beta.50)(typescript@5.9.2)(vue-tsc@2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.9.2)) - semver: 7.7.3 + semver: 7.7.2 tinyexec: 1.0.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 @@ -36056,7 +35968,7 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.1.3: {} + vue-component-type-helpers@3.1.4: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies:
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-v98v-ff95-f3cpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-68613ghsaADVISORY
- github.com/n8n-io/n8n/commit/08f332015153decdda3c37ad4fcb9f7ba13a7c79ghsax_refsource_MISCWEB
- github.com/n8n-io/n8n/commit/1c933358acef527ff61466e53268b41a04be1000ghsax_refsource_MISCWEB
- github.com/n8n-io/n8n/commit/39a2d1d60edde89674ca96dcbb3eb076ffff6316ghsax_refsource_MISCWEB
- github.com/n8n-io/n8n/security/advisories/GHSA-v98v-ff95-f3cpghsax_refsource_CONFIRMWEB
- www.akamai.com/blog/security-research/2026/feb/zerobot-malware-targets-n8n-automation-platformghsaWEB
- www.cisa.gov/known-exploited-vulnerabilities-catalogghsaWEB
News mentions
0No linked articles in our index yet.