T09 · Insecure Skill Coding Practices
- Location
handler.js:47- Finding
Predictable, Non-Exclusive Temporary Files Permit Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
handler.js, lines 47–57
Vulnerability Type: Insecure temporary-file creation
Risk Level: MediumVulnerable Code
js const tempDir = os.tmpdir(); const timestamp = Date.now(); const jsxPath = path.join(tempDir, `ps_script_${timestamp}.jsx`); fs.writeFileSync(jsxPath, ctx.params.script); let result; if (isWin) { const vbsPath = path.join(tempDir, `ps_bridge_${timestamp}.vbs`); fs.writeFileSync(vbsPath, VBS_CONTENT);Technical Analysis
The Skill constructs temporary JSX and VBS paths from
Date.now(), making their names predictable to another process on the same host. It then creates or truncates these files usingfs.writeFileSyncwithout exclusive creation.Because the operating-system temporary directory may be shared among users or processes, a local attacker can predict candidate filenames and pre-create symbolic links at those paths. When the Skill writes the temporary content, the write operation can follow the symbolic link and overwrite its target with the privileges of the Agent process. This is a time-of-check/time-of-use-style temporary-file vulnerability; no separate validation step prevents link traversal or an existing path from being reused.
Attack Path
- A local attacker monitors the clock and predicts upcoming names such as
ps_script_<timestamp>.jsxorps_bridge_<timestamp>.vbs. - The attacker creates candidate symbolic links in the shared temporary directory before the Skill writes its files.
- Each symbolic link points to a file the Agent process can modify.
- A user or automated workflow invokes
runScript. fs.writeFileSyncfollows the attacker-created link and truncates or overwrites the selected target.- Depending on the target, the attacker can cause data loss, configuration manipulation, or execution of attacker-influenced content by another component.
The exploit requires ...[truncated 724 chars]
- A local attacker monitors the clock and predicts upcoming names such as
- Remediation
View remediation
Remediation Suggestions
- Create a uniquely named private temporary directory with
fs.mkdtempSync(path.join(os.tmpdir(), 'photoshop-automator-')). - Store the JSX and VBS files inside that private directory using fixed internal names.
- Create files exclusively with
flag: 'wx'so existing paths are rejected rather than truncated. - Apply restrictive permissions, such as mode
0o600for files and0o700for the directory where supported. - Place execution and cleanup in a
try/finallyblock so all temporary artifacts are removed on success, process-launch failure, or unexpected exceptions. - Reject symbolic links or unexpected pre-existing entries if compatibility constraints prevent use of a private directory.
- Avoid relying on timestamps alone for uniqueness; use operating-system-backed secure temporary creation.
Example hardening pattern:
js const tempRoot = fs.mkdtempSync( path.join(os.tmpdir(), 'photoshop-automator-') ); try { const jsxPath = path.join(tempRoot, 'script.jsx'); fs.writeFileSync(jsxPath, ctx.params.script, { flag: 'wx', mode: 0o600 }); // Create the bridge with the same exclusive and restrictive options. // Execute Photoshop automation here. } finally { fs.rmSync(tempRoot, { recursive: true, force: true }); }- Create a uniquely named private temporary directory with
