From 17fb291aafebb900ad546bde96c548e0d9bf733c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 13 Aug 2026 07:55:07 +0200 Subject: [PATCH] fix(import): draw the extraction temp name from crypto randomness The extracted export.xml lands in the shared system tmpdir under a name built from the clock and Math.random, which is predictable enough for a local pre-creation or symlink attack to aim at. The name comes from crypto.randomBytes now. Flagged by code scanning on the import path. --- src/lib/import/unzip-export-xml.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/import/unzip-export-xml.ts b/src/lib/import/unzip-export-xml.ts index 0875a82a0..3a45b91a3 100644 --- a/src/lib/import/unzip-export-xml.ts +++ b/src/lib/import/unzip-export-xml.ts @@ -46,6 +46,7 @@ import { Transform } from "node:stream"; import { pipeline } from "node:stream/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; +import { randomBytes } from "node:crypto"; /** Signature bytes for the End-Of-Central-Directory record. */ const EOCD_SIGNATURE = 0x06054b50; @@ -202,9 +203,12 @@ export async function extractExportXml( }); } + // Unguessable temp name: the extraction target lives in the shared + // system tmpdir, and a predictable name (timestamp + Math.random) is + // what a local pre-creation or symlink attack needs. const xmlPath = join( tmpdir(), - `healthlog-import-${Date.now()}-${Math.random().toString(36).slice(2, 10)}.xml`, + `healthlog-import-${randomBytes(12).toString("hex")}.xml`, ); const xmlBytes = await streamEntryToFile( handle,