T09 · Insecure Skill Coding Practices
Error
- Location
- handler.js:68
- Finding
- Predictable and Non-Exclusive Temporary Files Allow File Overwrite and Script Substitution<![CDATA[ ## Vulnerability Details **File Location**: `handler.js:68-84` **Vulnerability Type**: Predictable temporary files, unsafe file creation, and time-of-check/time-of-use exposure **Risk Level**: High ### Vulnerable Code ```js const tempDir = os.tmpdir(); const timestamp = Date.now(); const jsxPath = path.join(tempDir, `adobe_script_${timestamp}.jsx`); // SECURITY WARNING: This executes arbitrary ExtendScript which has filesystem access. // The skill relies on the user/agent to verify the script content before execution. fs.writeFileSync(jsxPath, ctx.params.script); let result; if (isWin) { const vbsPath = path.join(tempDir, `adobe_bridge_${timestamp}.vbs`); fs.writeFileSync(vbsPath, VBS_TEMPLATE(config.win, jsxPath)); result = spawnSync('cscript', ['/nologo', vbsPath]); try { fs.unlinkSync(vbsPath); } catch (e) { } } else { const appleScript = APPLE_SCRIPT_TEMPLATE(config.mac, jsxPath); result = spawnSync('osascript', ['-e', appleScript]); } ``` ### Technical Analysis The handler creates JSX and VBS files directly in the shared operating-system temporary directory. Their names are generated solely from `Date.now()`, making them predictable and observable. The files are written with `fs.writeFileSync` without exclusive creation, a private parent directory, or explicit restrictive permissions. By default, `fs.writeFileSync` can truncate an existing file and follows filesystem links where the operating system permits this behavior. There is also a window between writing each temporary file and executing it. A local process operating under the same user account—or another local user where temporary-directory and platform protections permit—could pre-create, redirect, monitor, or replace one of these files. The JSX file is especially sensitive because Adobe ExtendScript has filesystem access and runs with the privileges of the user running the Adobe application. On Windows, replacement of the VBS bridge can additionally cause a ...[truncated 1789 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Create a private temporary directory for every invocation using `fs.mkdtempSync` with a random suffix. 2. Set the directory permissions to owner-only (`0700`) on platforms that support POSIX permissions. 3. Create temporary files with exclusive creation (`flag: "wx"`) and owner-only permissions (`0600`) so existing paths cannot be silently overwritten. 4. Keep all JSX and bridge files inside the private directory rather than directly under the shared OS temporary directory. 5. Place execution and cleanup in a `try`/`finally` block so files are removed even if writing, process creation, or output handling throws. 6. Where feasible, validate file ownership and type before execution and reject symbolic links or other unexpected filesystem objects. 7. Consider passing script data through a protected process channel when supported, avoiding temporary executable script files entirely. Example hardening pattern: ```js const privateDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adobe-automator-')); if (process.platform !== 'win32') { fs.chmodSync(privateDir, 0o700); } const jsxPath = path.join(privateDir, 'script.jsx'); try { fs.writeFileSync(jsxPath, ctx.params.script, { flag: 'wx', mode: 0o600 }); // Create any bridge file with the same exclusive and restrictive options, // then execute it from this private directory. } finally { fs.rmSync(privateDir, { recursive: true, force: true }); } ``` ]]>
