diff --git a/server/routes.test.ts b/server/routes.test.ts new file mode 100644 index 0000000..91c6af3 --- /dev/null +++ b/server/routes.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from "vitest"; +import crypto from "crypto"; + +// Helper function mirroring webhook signature logic in server/routes.ts +function computeWebhookSignature(data: any, customSecret?: string): string { + const hmacSecret = customSecret || process.env.IDSEC_HMAC_SECRET || "idsec_secret_salt"; + const payloadString = JSON.stringify(data); + return crypto.createHmac("sha256", hmacSecret).update(payloadString).digest("hex"); +} + +describe("Webhook HMAC signature calculation", () => { + it("should calculate signature using IDSEC_HMAC_SECRET when set", () => { + const data = { event: "webhook.test", id: 1 }; + const secret = "super_secret_env_key"; + + process.env.IDSEC_HMAC_SECRET = secret; + const signature = computeWebhookSignature(data); + const expected = crypto.createHmac("sha256", secret).update(JSON.stringify(data)).digest("hex"); + + expect(signature).toBe(expected); + delete process.env.IDSEC_HMAC_SECRET; + }); + + it("should fallback to default salt when IDSEC_HMAC_SECRET is unset", () => { + delete process.env.IDSEC_HMAC_SECRET; + const data = { event: "webhook.test", id: 1 }; + + const signature = computeWebhookSignature(data); + const expected = crypto.createHmac("sha256", "idsec_secret_salt").update(JSON.stringify(data)).digest("hex"); + + expect(signature).toBe(expected); + }); +}); diff --git a/server/routes.ts b/server/routes.ts index d10cf6b..2876b70 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -2450,10 +2450,12 @@ CSAF: ${baseUrl}/.well-known/csaf/provider-metadata.json return res.status(400).json({ message: "Missing required fields" }); } - // Create webhook payload with cryptographic signature + // SECURITY: Avoid hardcoding cryptographic HMAC secret salts in source code. + // Load secret from environment variable IDSEC_HMAC_SECRET with a fallback for local development. + const hmacSecret = process.env.IDSEC_HMAC_SECRET || "idsec_secret_salt"; const payloadId = uuidv4(); const payloadString = JSON.stringify(data); - const signature = crypto.createHmac("sha256", "idsec_secret_salt").update(payloadString).digest("hex"); + const signature = crypto.createHmac("sha256", hmacSecret).update(payloadString).digest("hex"); const payload = { id: payloadId,