security(crypto): replace SHA-1 with SHA-256 in all hash operations

SHA-1 is cryptographically broken and vulnerable to collision
attacks. Replace all internal usages with SHA-256:

- sandbox session key slugs (shared.ts)
- sandbox config change detection (config-hash.ts)
- tool call ID generation (tool-call-id.ts)
- gateway lock file naming (gateway-lock.ts)

All hashes are ephemeral (session-scoped slugs, lock filenames,
tool IDs) so the algorithm change has no persistence impact.

Fixes #2994
This commit is contained in:
Leszek Szpunar 2026-01-30 12:49:20 +01:00
parent fa9ec6e854
commit 7e2f656cf8
5 changed files with 5 additions and 5 deletions

View File

@ -49,5 +49,5 @@ function primitiveToString(value: unknown): string {
export function computeSandboxConfigHash(input: SandboxHashInput): string {
const payload = normalizeForHash(input);
const raw = JSON.stringify(payload);
return crypto.createHash("sha1").update(raw).digest("hex");
return crypto.createHash("sha256").update(raw).digest("hex");
}

View File

@ -7,7 +7,7 @@ import { resolveAgentIdFromSessionKey } from "../agent-scope.js";
export function slugifySessionKey(value: string) {
const trimmed = value.trim() || "session";
const hash = crypto.createHash("sha1").update(trimmed).digest("hex").slice(0, 8);
const hash = crypto.createHash("sha256").update(trimmed).digest("hex").slice(0, 8);
const safe = trimmed
.toLowerCase()
.replace(/[^a-z0-9._-]+/g, "-")

View File

@ -40,7 +40,7 @@ export function isValidCloudCodeAssistToolId(id: string, mode: ToolCallIdMode =
}
function shortHash(text: string, length = 8): string {
return createHash("sha1").update(text).digest("hex").slice(0, length);
return createHash("sha256").update(text).digest("hex").slice(0, length);
}
function makeUniqueToolId(params: { id: string; used: Set<string>; mode: ToolCallIdMode }): string {

View File

@ -29,7 +29,7 @@ async function makeEnv() {
function resolveLockPath(env: NodeJS.ProcessEnv) {
const stateDir = resolveStateDir(env);
const configPath = resolveConfigPath(env, stateDir);
const hash = createHash("sha1").update(configPath).digest("hex").slice(0, 8);
const hash = createHash("sha256").update(configPath).digest("hex").slice(0, 8);
const lockDir = resolveGatewayLockDir();
return { lockPath: path.join(lockDir, `gateway.${hash}.lock`), configPath };
}

View File

@ -150,7 +150,7 @@ async function readLockPayload(lockPath: string): Promise<LockPayload | null> {
function resolveGatewayLockPath(env: NodeJS.ProcessEnv) {
const stateDir = resolveStateDir(env);
const configPath = resolveConfigPath(env, stateDir);
const hash = createHash("sha1").update(configPath).digest("hex").slice(0, 8);
const hash = createHash("sha256").update(configPath).digest("hex").slice(0, 8);
const lockDir = resolveGatewayLockDir();
const lockPath = path.join(lockDir, `gateway.${hash}.lock`);
return { lockPath, configPath };