Merge pull request #14090 from Budibase/budi-8417-check-error-responses-in-middleware-for-environment
Detect secrets in error messages.
This commit is contained in:
commit
b7d58e29d2
|
@ -1 +1 @@
|
||||||
Subproject commit ff16525b73c5751d344f5c161a682609c0a993f2
|
Subproject commit b03e584e465f620b49a1b688ff4afc973e6c0758
|
|
@ -205,6 +205,23 @@ const environment = {
|
||||||
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EnvironmentKey = keyof typeof environment
|
||||||
|
export const SECRETS: EnvironmentKey[] = [
|
||||||
|
"API_ENCRYPTION_KEY",
|
||||||
|
"BB_ADMIN_USER_PASSWORD",
|
||||||
|
"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",
|
||||||
|
"OPENAI_API_KEY",
|
||||||
|
"REDIS_PASSWORD",
|
||||||
|
]
|
||||||
|
|
||||||
// clean up any environment variable edge cases
|
// clean up any environment variable edge cases
|
||||||
for (let [key, value] of Object.entries(environment)) {
|
for (let [key, value] of Object.entries(environment)) {
|
||||||
// handle the edge case of "0" to disable an environment variable
|
// handle the edge case of "0" to disable an environment variable
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { APIError } from "@budibase/types"
|
import { APIError } from "@budibase/types"
|
||||||
import * as errors from "../errors"
|
import * as errors from "../errors"
|
||||||
import environment from "../environment"
|
import environment from "../environment"
|
||||||
|
import { stringContainsSecret } from "../security/secrets"
|
||||||
|
|
||||||
export async function errorHandling(ctx: any, next: any) {
|
export async function errorHandling(ctx: any, next: any) {
|
||||||
try {
|
try {
|
||||||
|
@ -17,11 +18,19 @@ export async function errorHandling(ctx: any, next: any) {
|
||||||
|
|
||||||
let error: APIError = {
|
let error: APIError = {
|
||||||
message: err.message,
|
message: err.message,
|
||||||
status: status,
|
status,
|
||||||
validationErrors: err.validation,
|
validationErrors: err.validation,
|
||||||
error: errors.getPublicError(err),
|
error: errors.getPublicError(err),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stringContainsSecret(JSON.stringify(error))) {
|
||||||
|
error = {
|
||||||
|
message: "Unexpected error",
|
||||||
|
status,
|
||||||
|
error: "Unexpected error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (environment.isTest() && ctx.headers["x-budibase-include-stacktrace"]) {
|
if (environment.isTest() && ctx.headers["x-budibase-include-stacktrace"]) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
error.stack = err.stack
|
error.stack = err.stack
|
||||||
|
|
|
@ -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" || value === "") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.includes(value)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue