mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(security): use SHA-256 for Notion per-caller cache namespace hash (was 32-bit FNV)
Security-review follow-up: the per-caller namespace hash is a security boundary (cross-tenant cache isolation), so a 32-bit FNV digest was too collision-prone — an attacker could craft a cookie colliding into a victim's namespace. SHA-256 (128-bit prefix) makes accidental + crafted collisions infeasible. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
* - Optional client-supplied continuity via body (`notion_thread_id`/`thread_id`)
|
||||
* or the `X-Notion-Thread-Id` header (via `ExecuteInput.clientHeaders`).
|
||||
*/
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { randomUUID, createHash } from "node:crypto";
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
|
||||
@@ -439,10 +439,10 @@ export function readClientThreadId(
|
||||
export function hashNotionCallerCookie(cookie: string): string {
|
||||
const raw = (cookie || "").trim();
|
||||
if (!raw) return "anon";
|
||||
let hash = 0x811c9dc5;
|
||||
for (let i = 0; i < raw.length; i++) {
|
||||
hash ^= raw.charCodeAt(i);
|
||||
hash = Math.imul(hash, 0x01000193) >>> 0;
|
||||
}
|
||||
return hash.toString(16).padStart(8, "0");
|
||||
// SHA-256 (128-bit prefix) rather than a 32-bit FNV digest: this hash is a
|
||||
// SECURITY boundary (per-caller cache isolation), so it must be collision-
|
||||
// resistant — a 32-bit space is birthday-crackable, letting an attacker craft
|
||||
// a cookie that lands in a victim's namespace. crypto SHA-256 makes both
|
||||
// accidental and crafted collisions infeasible; the raw cookie is never stored.
|
||||
return createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user