T08 · Insecure Dependencies
- Location
scripts/compress.cjs:13- Finding
Unsafe Dependency Loading from a Shared Temporary Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/compress.cjs, lines 13–18
Vulnerability Type: Unsafe third-party module resolution from a shared, writable directory
Risk Level: HighVulnerable Code
js let lzstring; try { lzstring = require("lz-string"); } catch { // Try local or relative try { lzstring = require("/tmp/node_modules/lz-string"); } catch { lzstring = require(require("path").join(process.cwd(), "node_modules", "lz-string")); } }Technical Analysis
When standard Node.js resolution for
lz-stringfails, the script explicitly loads the dependency from/tmp/node_modules/lz-string. On typical multi-user Unix-like systems,/tmpis shared and writable. An attacker with local write access can create that module path and place attacker-controlled JavaScript in it.Node.js executes a module's top-level code during
require(). Consequently, the malicious module executes before the script reads or converts the drawing. No package manifest, lockfile, integrity verification, ownership check, or trusted-path validation is present to authenticate the fallback dependency.The final fallback based on
process.cwd()also makes dependency selection depend on the caller-controlled working directory. If the normal and/tmpresolutions fail, invoking the script from a directory containing an attacker-controllednode_modules/lz-stringcan produce the same code-execution result.Attack Path
- An attacker obtains write access to the shared
/tmpdirectory, or controls the directory from which the script will be launched. - The attacker creates a malicious module at
/tmp/node_modules/lz-string/index.js, or atnode_modules/lz-stringbeneath the controlled working directory. - The legitimate
lz-stringdependency is absent or cannot be resolved through normal Node.js module lookup. - A victim invokes
node scripts/compress.cjs input.excalidraw. - The fallback
require()resolves and executes the a ...[truncated 773 chars]
- An attacker obtains write access to the shared
- Remediation
View remediation
Remediation Suggestions
- Remove both the hard-coded
/tmp/node_modules/lz-stringfallback and theprocess.cwd()-based fallback. - Declare
lz-stringas a direct dependency in a project-localpackage.json. - Commit a lockfile and use deterministic installation such as
npm ci. - Load the dependency only through standard resolution from the Skill's trusted installation tree:
js let lzstring; try { lzstring = require("lz-string"); } catch (error) { console.error("Required dependency 'lz-string' is not installed."); process.exit(1); }- Fail closed when the trusted dependency is unavailable rather than searching writable or caller-controlled locations.
- Pin and routinely audit the dependency version. Where deployment controls permit it, verify installed package integrity and ensure the Skill directory is not writable by untrusted users.
- Run the conversion script with least privilege and without unnecessary credentials in its environment.
- Remove both the hard-coded
