Skip to content

security: mkdtempSync for all scratch dirs (fixes 9 CodeQL insecure-temp-file alerts)#20

Merged
askalf merged 1 commit into
masterfrom
fix/insecure-temp-files
Jul 12, 2026
Merged

security: mkdtempSync for all scratch dirs (fixes 9 CodeQL insecure-temp-file alerts)#20
askalf merged 1 commit into
masterfrom
fix/insecure-temp-files

Conversation

@askalf

@askalf askalf commented Jul 12, 2026

Copy link
Copy Markdown
Owner

What

All 9 open CodeQL js/insecure-temporary-file alerts (#13#21) share one root cause: scratch paths built from a predictable name — path.join(os.tmpdir(), '<prefix>-' + process.pid). A local attacker can pre-create or symlink that path before the write.

This switches every such site to fs.mkdtempSync(path.join(os.tmpdir(), '<prefix>-')), which atomically creates an unpredictable, 0700 directory.

Changes

File Alert(s) Fix
demo.mjs 13, 14 HOMEmkdtempSync; drop redundant mkdirSync
test/stack.test.mjs 20, 21 HOMEmkdtempSync; drop redundant mkdirSync
audit-trail.mjs 15, 16, 17 runTrilogy() default homemkdtempSync (keeps mkdirSync(home) for caller-supplied homes)
test/audit.test.mjs 19 the 4 caller-supplied homes → mkdtempSync, so the interprocedural write in runTrilogy has no predictable source
mcp.mjs 18 write the manifest into a mkdtempSync dir, rmSync the dir in finally; predictable pid+hash filename and the now-dead hashStr helper removed

Also normalizes demo/mcp-demo.mjs and test/mcp.test.mjs — same predictable pattern, not yet flagged — so the class can't resurface on the next scan.

Verification

  • npm test16/16 pass
  • node demo.mjs and node demo/mcp-demo.mjs run clean

No public API change; the composed gate's behavior is unchanged.

…insecure-temporary-file)

Every demo/test/MCP scratch path was built from a predictable name
(os.tmpdir() + a fixed prefix + process.pid), which a local attacker can
pre-create or symlink ahead of the write. Switch all of them to
fs.mkdtempSync(path.join(os.tmpdir(), '<prefix>-')), which creates an
unpredictable 0700 directory atomically.

- demo.mjs, test/stack.test.mjs, demo/mcp-demo.mjs, test/mcp.test.mjs:
  HOME/KH now mkdtempSync; the redundant mkdirSync is dropped.
- audit-trail.mjs runTrilogy(): default home is mkdtempSync; the explicit
  mkdirSync(home) stays so caller-supplied homes are still created.
- test/audit.test.mjs: the four caller-supplied homes are mkdtempSync too,
  so the interprocedural write in runTrilogy has no predictable source.
- mcp.mjs canon_scan: write the manifest into a mkdtempSync dir and rmSync
  the whole dir in finally; the predictable pid+hash filename (and the now
  unused hashStr helper) are removed.

Also normalizes demo/mcp-demo.mjs and test/mcp.test.mjs, which used the
same pattern but were not yet flagged, so the class can't resurface.

Tests: 16/16 pass; demo.mjs and demo/mcp-demo.mjs run clean.
@askalf askalf merged commit 0c51195 into master Jul 12, 2026
3 checks passed
@askalf askalf deleted the fix/insecure-temp-files branch July 12, 2026 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant