From 84fe77868426cb78f90997e783b528b548e028ae Mon Sep 17 00:00:00 2001 From: NLmejiro Date: Wed, 1 Apr 2026 13:17:05 +0000 Subject: [PATCH 1/4] fix: specify authTagLength in AES-GCM decipheriv calls Fixes missing authTagLength parameter in createDecipheriv calls using AES-256-GCM mode. Without explicit tag length specification, the application may be tricked into accepting shorter authentication tags, potentially allowing ciphertext spoofing. CWE-310: Cryptographic Issues (gcm-no-tag-length) --- apps/sim/lib/api-key/crypto.ts | 2 +- apps/sim/lib/core/security/encryption.ts | 2 +- packages/db/scripts/migrate-block-api-keys-to-byok.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sim/lib/api-key/crypto.ts b/apps/sim/lib/api-key/crypto.ts index 3cac7ee0f5c..21b945bc838 100644 --- a/apps/sim/lib/api-key/crypto.ts +++ b/apps/sim/lib/api-key/crypto.ts @@ -81,7 +81,7 @@ export async function decryptApiKey(encryptedValue: string): Promise<{ decrypted const authTag = Buffer.from(authTagHex, 'hex') try { - const decipher = createDecipheriv('aes-256-gcm', key, iv) + const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 }) decipher.setAuthTag(authTag) let decrypted = decipher.update(encrypted, 'hex', 'utf8') diff --git a/apps/sim/lib/core/security/encryption.ts b/apps/sim/lib/core/security/encryption.ts index ab4fcdab71d..23f074bcf5f 100644 --- a/apps/sim/lib/core/security/encryption.ts +++ b/apps/sim/lib/core/security/encryption.ts @@ -54,7 +54,7 @@ export async function decryptSecret(encryptedValue: string): Promise<{ decrypted const authTag = Buffer.from(authTagHex, 'hex') try { - const decipher = createDecipheriv('aes-256-gcm', key, iv) + const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 }) decipher.setAuthTag(authTag) let decrypted = decipher.update(encrypted, 'hex', 'utf8') diff --git a/packages/db/scripts/migrate-block-api-keys-to-byok.ts b/packages/db/scripts/migrate-block-api-keys-to-byok.ts index 06a507a5e92..34c5bf64499 100644 --- a/packages/db/scripts/migrate-block-api-keys-to-byok.ts +++ b/packages/db/scripts/migrate-block-api-keys-to-byok.ts @@ -146,7 +146,7 @@ async function decryptSecret(encryptedValue: string): Promise { const iv = Buffer.from(ivHex, 'hex') const authTag = Buffer.from(authTagHex, 'hex') - const decipher = createDecipheriv('aes-256-gcm', key, iv) + const decipher = createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 }) decipher.setAuthTag(authTag) let decrypted = decipher.update(encrypted, 'hex', 'utf8') From 9dcb2ac9947731c18384fb03bd50a4a5ab5ecb23 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 1 Apr 2026 10:24:57 -0700 Subject: [PATCH 2/4] fix: specify authTagLength on createCipheriv calls for AES-GCM consistency Complements #3881 by adding explicit authTagLength: 16 to the encrypt side as well, ensuring both cipher and decipher specify the tag length. Co-Authored-By: Claude Opus 4.6 --- apps/sim/lib/api-key/crypto.ts | 2 +- apps/sim/lib/core/security/encryption.ts | 2 +- packages/db/scripts/migrate-block-api-keys-to-byok.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sim/lib/api-key/crypto.ts b/apps/sim/lib/api-key/crypto.ts index 21b945bc838..9cea83aaba6 100644 --- a/apps/sim/lib/api-key/crypto.ts +++ b/apps/sim/lib/api-key/crypto.ts @@ -36,7 +36,7 @@ export async function encryptApiKey(apiKey: string): Promise<{ encrypted: string } const iv = randomBytes(16) - const cipher = createCipheriv('aes-256-gcm', key, iv) + const cipher = createCipheriv('aes-256-gcm', key, iv, { authTagLength: 16 }) let encrypted = cipher.update(apiKey, 'utf8', 'hex') encrypted += cipher.final('hex') diff --git a/apps/sim/lib/core/security/encryption.ts b/apps/sim/lib/core/security/encryption.ts index 23f074bcf5f..088ed68b8b8 100644 --- a/apps/sim/lib/core/security/encryption.ts +++ b/apps/sim/lib/core/security/encryption.ts @@ -21,7 +21,7 @@ export async function encryptSecret(secret: string): Promise<{ encrypted: string const iv = randomBytes(16) const key = getEncryptionKey() - const cipher = createCipheriv('aes-256-gcm', key, iv) + const cipher = createCipheriv('aes-256-gcm', key, iv, { authTagLength: 16 }) let encrypted = cipher.update(secret, 'utf8', 'hex') encrypted += cipher.final('hex') diff --git a/packages/db/scripts/migrate-block-api-keys-to-byok.ts b/packages/db/scripts/migrate-block-api-keys-to-byok.ts index 34c5bf64499..88ee98e2204 100644 --- a/packages/db/scripts/migrate-block-api-keys-to-byok.ts +++ b/packages/db/scripts/migrate-block-api-keys-to-byok.ts @@ -125,7 +125,7 @@ function getEncryptionKeyBuffer(): Buffer { async function encryptSecret(secret: string): Promise { const iv = randomBytes(16) const key = getEncryptionKeyBuffer() - const cipher = createCipheriv('aes-256-gcm', key, iv) + const cipher = createCipheriv('aes-256-gcm', key, iv, { authTagLength: 16 }) let encrypted = cipher.update(secret, 'utf8', 'hex') encrypted += cipher.final('hex') const authTag = cipher.getAuthTag() From 276c281efcaf4fbb530549317bb05cc2c1819cde Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 1 Apr 2026 10:29:17 -0700 Subject: [PATCH 3/4] refactor: clean up crypto modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix error: any → error: unknown with proper type guard in encryption.ts - Eliminate duplicate iv.toString('hex') calls in both encrypt functions - Remove redundant string split in decryptApiKey (was splitting twice) Co-Authored-By: Claude Opus 4.6 --- apps/sim/lib/api-key/crypto.ts | 14 ++++++++------ apps/sim/lib/core/security/encryption.ts | 11 +++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/sim/lib/api-key/crypto.ts b/apps/sim/lib/api-key/crypto.ts index 9cea83aaba6..aeee9097218 100644 --- a/apps/sim/lib/api-key/crypto.ts +++ b/apps/sim/lib/api-key/crypto.ts @@ -41,11 +41,12 @@ export async function encryptApiKey(apiKey: string): Promise<{ encrypted: string encrypted += cipher.final('hex') const authTag = cipher.getAuthTag() + const ivHex = iv.toString('hex') // Format: iv:encrypted:authTag return { - encrypted: `${iv.toString('hex')}:${encrypted}:${authTag.toString('hex')}`, - iv: iv.toString('hex'), + encrypted: `${ivHex}:${encrypted}:${authTag.toString('hex')}`, + iv: ivHex, } } @@ -55,8 +56,10 @@ export async function encryptApiKey(apiKey: string): Promise<{ encrypted: string * @returns A promise that resolves to an object containing the decrypted API key */ export async function decryptApiKey(encryptedValue: string): Promise<{ decrypted: string }> { + const parts = encryptedValue.split(':') + // Check if this is actually encrypted (contains colons) - if (!encryptedValue.includes(':') || encryptedValue.split(':').length !== 3) { + if (parts.length !== 3) { // This is a plain text key, return as-is return { decrypted: encryptedValue } } @@ -68,10 +71,9 @@ export async function decryptApiKey(encryptedValue: string): Promise<{ decrypted return { decrypted: encryptedValue } } - const parts = encryptedValue.split(':') const ivHex = parts[0] - const authTagHex = parts[parts.length - 1] - const encrypted = parts.slice(1, -1).join(':') + const authTagHex = parts[2] + const encrypted = parts[1] if (!ivHex || !encrypted || !authTagHex) { throw new Error('Invalid encrypted API key format. Expected "iv:encrypted:authTag"') diff --git a/apps/sim/lib/core/security/encryption.ts b/apps/sim/lib/core/security/encryption.ts index 088ed68b8b8..811a60ada48 100644 --- a/apps/sim/lib/core/security/encryption.ts +++ b/apps/sim/lib/core/security/encryption.ts @@ -26,11 +26,12 @@ export async function encryptSecret(secret: string): Promise<{ encrypted: string encrypted += cipher.final('hex') const authTag = cipher.getAuthTag() + const ivHex = iv.toString('hex') // Format: iv:encrypted:authTag return { - encrypted: `${iv.toString('hex')}:${encrypted}:${authTag.toString('hex')}`, - iv: iv.toString('hex'), + encrypted: `${ivHex}:${encrypted}:${authTag.toString('hex')}`, + iv: ivHex, } } @@ -61,8 +62,10 @@ export async function decryptSecret(encryptedValue: string): Promise<{ decrypted decrypted += decipher.final('utf8') return { decrypted } - } catch (error: any) { - logger.error('Decryption error:', { error: error.message }) + } catch (error: unknown) { + logger.error('Decryption error:', { + error: error instanceof Error ? error.message : 'Unknown error', + }) throw error } } From 5686d57eafa2de01ffcb4359f952dc03972cd299 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 1 Apr 2026 10:32:53 -0700 Subject: [PATCH 4/4] new turborepo version --- bun.lock | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bun.lock b/bun.lock index 181248e1ee7..e773f35d67e 100644 --- a/bun.lock +++ b/bun.lock @@ -10,7 +10,7 @@ "glob": "13.0.0", "husky": "9.1.7", "lint-staged": "16.0.0", - "turbo": "2.9.1", + "turbo": "2.9.3", }, }, "apps/docs": { @@ -1486,17 +1486,17 @@ "@trigger.dev/sdk": ["@trigger.dev/sdk@4.4.3", "", { "dependencies": { "@opentelemetry/api": "1.9.0", "@opentelemetry/semantic-conventions": "1.36.0", "@trigger.dev/core": "4.4.3", "chalk": "^5.2.0", "cronstrue": "^2.21.0", "debug": "^4.3.4", "evt": "^2.4.13", "slug": "^6.0.0", "ulid": "^2.3.0", "uncrypto": "^0.1.3", "uuid": "^9.0.0", "ws": "^8.11.0" }, "peerDependencies": { "ai": "^4.2.0 || ^5.0.0 || ^6.0.0", "zod": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["ai"] }, "sha512-ghJkak+PTBJJ9HiHMcnahJmzjsgCzYiIHu5Qj5R7I9q5LS6i7mkx169rB/tOE9HLadd4HSu3yYA5DrH4wXhZuw=="], - "@turbo/darwin-64": ["@turbo/darwin-64@2.9.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-d1zTcIf6VWT7cdfjhi0X36C2PRsUi2HdEwYzVgkLHmuuYtL+1Y1Zu3JdlouoB/NjG2vX3q4NnKLMNhDOEweoIg=="], + "@turbo/darwin-64": ["@turbo/darwin-64@2.9.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-P8foouaP+y/p+hhEGBoZpzMbpVvUMwPjDpcy6wN7EYfvvyISD1USuV27qWkczecihwuPJzQ1lDBuL8ERcavTyg=="], - "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AwJ4mA++Kpem33Lcov093hS1LrgqbKxqq5FCReoqsA8ayEG6eAJAo8ItDd9qQTdBiXxZH8GHCspLAMIe1t3Xyw=="], + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-SIzEkvtNdzdI50FJDaIQ6kQGqgSSdFPcdn0wqmmONN6iGKjy6hsT+EH99GP65FsfV7DLZTh2NmtTIRl2kdoz5Q=="], - "@turbo/linux-64": ["@turbo/linux-64@2.9.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HT9SjKkjEw9uvlgly/qwCGEm4wOXOwQPSPS+wkg+/O1Qan3F1uU/0PFYzxl3m4lfuV3CP9wr2Dq5dPrUX+B9Ag=="], + "@turbo/linux-64": ["@turbo/linux-64@2.9.3", "", { "os": "linux", "cpu": "x64" }, "sha512-pLRwFmcHHNBvsCySLS6OFabr/07kDT2pxEt/k6eBf/3asiVQZKJ7Rk88AafQx2aYA641qek4RsXvYO3JYpiBug=="], - "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+4s5GZs3kjxc1KMhLBhoQy4UBkXjOhgidA9ipNllkA4JLivSqUCuOgU1Xbyp6vzYrsqHJ9vvwo/2mXgEtD6ZHg=="], + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-gy6ApUroC2Nzv+qjGtE/uPNkhHAFU4c8God+zd5Aiv9L9uBgHlxVJpHT3XWl5xwlJZ2KWuMrlHTaS5kmNB+q1Q=="], - "@turbo/windows-64": ["@turbo/windows-64@2.9.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ZO7GCyQd5HV564XWHc9KysjanFfM3DmnWquyEByu+hQMq42g9OMU/fYOCfHS6Xj2aXkIg2FHJeRV+iAck2YrbQ=="], + "@turbo/windows-64": ["@turbo/windows-64@2.9.3", "", { "os": "win32", "cpu": "x64" }, "sha512-d0YelTX6hAsB7kIEtGB3PzIzSfAg3yDoUlHwuwJc3adBXUsyUIs0YLG+1NNtuhcDOUGnWQeKUoJ2pGWvbpRj7w=="], - "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-BjX2fdz38mBb/H94JXrD5cJ+mEq8NmsCbYdC42JzQebJ0X8EdNgyFoEhOydPGViOmaRmhhdZnPZKKn6wahSpcA=="], + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-/08CwpKJl3oRY8nOlh2YgilZVJDHsr60XTNxRhuDeuFXONpUZ5X+Nv65izbG/xBew9qxcJFbDX9/sAmAX+ITcQ=="], "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], @@ -3632,7 +3632,7 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.9.1", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.1", "@turbo/darwin-arm64": "2.9.1", "@turbo/linux-64": "2.9.1", "@turbo/linux-arm64": "2.9.1", "@turbo/windows-64": "2.9.1", "@turbo/windows-arm64": "2.9.1" }, "bin": { "turbo": "bin/turbo" } }, "sha512-TO9du8MwLTAKoXcGezekh9cPJabJUb0+8KxtpMR6kXdRASrmJ8qXf2GkVbCREgzbMQakzfNcux9cZtxheDY4RQ=="], + "turbo": ["turbo@2.9.3", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.3", "@turbo/darwin-arm64": "2.9.3", "@turbo/linux-64": "2.9.3", "@turbo/linux-arm64": "2.9.3", "@turbo/windows-64": "2.9.3", "@turbo/windows-arm64": "2.9.3" }, "bin": { "turbo": "bin/turbo" } }, "sha512-J/VUvsGRykPb9R8Kh8dHVBOqioDexLk9BhLCU/ZybRR+HN9UR3cURdazFvNgMDt9zPP8TF6K73Z+tplfmi0PqQ=="], "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="], diff --git a/package.json b/package.json index 84fff1afa0b..9cd7279b997 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "glob": "13.0.0", "husky": "9.1.7", "lint-staged": "16.0.0", - "turbo": "2.9.1" + "turbo": "2.9.3" }, "lint-staged": { "*.{js,jsx,ts,tsx,json,css,scss}": [