From 77d27bc826e4e91c2c589a62cbb6b997cacccd16 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 17 Apr 2026 17:42:34 +0100 Subject: [PATCH 1/2] fix(core): Guard against undefined config properties in credential overwrites (#28573) Co-authored-by: Claude Sonnet 4.6 --- .../__tests__/credentials-overwrites.test.ts | 30 +++++++++++++++++++ packages/cli/src/credentials-overwrites.ts | 14 ++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/__tests__/credentials-overwrites.test.ts b/packages/cli/src/__tests__/credentials-overwrites.test.ts index 247472b2580..4359dd28531 100644 --- a/packages/cli/src/__tests__/credentials-overwrites.test.ts +++ b/packages/cli/src/__tests__/credentials-overwrites.test.ts @@ -113,6 +113,36 @@ describe('CredentialsOverwrites', () => { expect(result).toEqual(data); }); + it('should not crash when skipTypes is undefined', () => { + // Simulate version mismatch where skipTypes is not present on the config object + globalConfig.credentials.overwrite.skipTypes = + undefined as unknown as CommaSeparatedStringArray; + + const result = credentialsOverwrites.applyOverwrite('test', { + username: '', + password: '', + }); + + expect(result).toEqual({ username: 'user', password: 'pass' }); + }); + + it('should not crash when overwrite config object is undefined', () => { + // Simulate a DI/version mismatch where the nested overwrite config is undefined + const savedOverwrite = globalConfig.credentials.overwrite; + globalConfig.credentials.overwrite = undefined as never; + + try { + const result = credentialsOverwrites.applyOverwrite('test', { + username: '', + password: '', + }); + + expect(result).toEqual({ username: 'user', password: 'pass' }); + } finally { + globalConfig.credentials.overwrite = savedOverwrite; + } + }); + describe('N8N_SKIP_CREDENTIAL_OVERWRITE', () => { beforeEach(() => { globalConfig.credentials.overwrite.skipTypes = [ diff --git a/packages/cli/src/credentials-overwrites.ts b/packages/cli/src/credentials-overwrites.ts index a2f6fb63901..632d8f7dfa9 100644 --- a/packages/cli/src/credentials-overwrites.ts +++ b/packages/cli/src/credentials-overwrites.ts @@ -147,7 +147,7 @@ export class CredentialsOverwrites { // customized (any overwrite field has a non-empty value that differs from // the overwrite value). Since overwrites are never persisted to the DB, // any non-empty stored value that differs from the overwrite is user-set. - if (this.globalConfig.credentials.overwrite.skipTypes.includes(type)) { + if (this.globalConfig.credentials.overwrite?.skipTypes?.includes(type)) { const isFieldCustomized = (key: string) => { const storedValue = data[key]; return ( @@ -208,11 +208,17 @@ export class CredentialsOverwrites { private get(name: string): ICredentialDataDecryptedObject | undefined { const parentTypes = this.credentialTypes.getParentTypes(name); - return [name, ...parentTypes] + const entries = [name, ...parentTypes] .reverse() .map((type) => this.overwriteData[type]) - .filter((type) => !!type) - .reduce((acc, current) => Object.assign(acc, current), {}); + .filter((type): type is ICredentialDataDecryptedObject => !!type); + + if (entries.length === 0) return undefined; + + return entries.reduce( + (acc, current) => Object.assign(acc, current), + {} as ICredentialDataDecryptedObject, + ); } getAll(): ICredentialsOverwrite { From ff950e5840214c515d413b45f174d9638a51dd39 Mon Sep 17 00:00:00 2001 From: RomanDavydchuk Date: Fri, 17 Apr 2026 20:09:14 +0300 Subject: [PATCH 2/2] fix: Link to n8n website broken in n8n forms (#28627) --- packages/core/src/__tests__/html-sandbox.test.ts | 2 +- packages/core/src/html-sandbox.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/__tests__/html-sandbox.test.ts b/packages/core/src/__tests__/html-sandbox.test.ts index 1d484248437..b6946efd87d 100644 --- a/packages/core/src/__tests__/html-sandbox.test.ts +++ b/packages/core/src/__tests__/html-sandbox.test.ts @@ -52,7 +52,7 @@ describe('getHtmlSandboxCSP', () => { it('should return correct CSP sandbox directive', () => { const csp = getHtmlSandboxCSP(); expect(csp).toBe( - 'sandbox allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols', + 'sandbox allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols', ); }); diff --git a/packages/core/src/html-sandbox.ts b/packages/core/src/html-sandbox.ts index c2f93c36db0..5fbfa1f31bc 100644 --- a/packages/core/src/html-sandbox.ts +++ b/packages/core/src/html-sandbox.ts @@ -13,5 +13,5 @@ export const isFormHtmlSandboxingDisabled = () => { * Returns the CSP header value that sandboxes the HTML page into a separate origin. */ export const getHtmlSandboxCSP = (): string => { - return 'sandbox allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-presentation allow-scripts allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols'; + return 'sandbox allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols'; };