Detect secrets in error messages.

This commit is contained in:
Sam Rose 2024-07-03 15:25:36 +01:00
parent 901428fc9c
commit 253110ac6f
No known key found for this signature in database
4 changed files with 80 additions and 1 deletions

View File

@ -205,6 +205,21 @@ const environment = {
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
}
type EnvironmentKey = keyof typeof environment
export const SECRETS: EnvironmentKey[] = [
"API_ENCRYPTION_KEY",
"COUCH_DB_PASSWORD",
"COUCH_DB_SQL_URL",
"COUCH_DB_URL",
"GOOGLE_CLIENT_SECRET",
"INTERNAL_API_KEY_FALLBACK",
"INTERNAL_API_KEY",
"JWT_SECRET",
"MINIO_ACCESS_KEY",
"MINIO_SECRET_KEY",
"REDIS_PASSWORD",
]
// clean up any environment variable edge cases
for (let [key, value] of Object.entries(environment)) {
// handle the edge case of "0" to disable an environment variable

View File

@ -1,6 +1,7 @@
import { APIError } from "@budibase/types"
import * as errors from "../errors"
import environment from "../environment"
import { stringContainsSecret } from "../security/secrets"
export async function errorHandling(ctx: any, next: any) {
try {
@ -17,7 +18,7 @@ export async function errorHandling(ctx: any, next: any) {
let error: APIError = {
message: err.message,
status: status,
status,
validationErrors: err.validation,
error: errors.getPublicError(err),
}
@ -27,6 +28,14 @@ export async function errorHandling(ctx: any, next: any) {
error.stack = err.stack
}
if (stringContainsSecret(JSON.stringify(error))) {
error = {
message: "Unexpected error",
status,
error: "Unexpected error",
}
}
ctx.body = error
}
}

View File

@ -0,0 +1,20 @@
import environment, { SECRETS } from "../environment"
export function stringContainsSecret(str: string) {
if (str.includes("-----BEGIN PRIVATE KEY-----")) {
return true
}
for (const key of SECRETS) {
const value = environment[key]
if (typeof value !== "string") {
continue
}
if (str.includes(value)) {
return true
}
}
return false
}

View File

@ -0,0 +1,35 @@
import { randomUUID } from "crypto"
import environment, { SECRETS } from "../../environment"
import { stringContainsSecret } from "../secrets"
describe("secrets", () => {
describe("stringContainsSecret", () => {
it.each(SECRETS)("detects that a string contains a secret in: %s", key => {
const needle = randomUUID()
const haystack = `this is a secret: ${needle}`
const old = environment[key]
environment._set(key, needle)
try {
expect(stringContainsSecret(haystack)).toBe(true)
} finally {
environment._set(key, old)
}
})
it.each(SECRETS)(
"detects that a string does not contain a secret in: %s",
key => {
const needle = randomUUID()
const haystack = `this does not contain a secret`
const old = environment[key]
environment._set(key, needle)
try {
expect(stringContainsSecret(haystack)).toBe(false)
} finally {
environment._set(key, old)
}
}
)
})
})