T07 · Tool Hijacking and Spoofing
- Location
src/skill.mjs:4- Finding
Working-Directory Executable Hijacking in Skill Wrapper
- Content
View full analysis
Vulnerability Details
File Location:
src/skill.mjs, lines 4-7
Vulnerability Type: Working-directory script hijacking
Risk Level: HighVulnerable Code
js const result = spawnSync("node", ["./src/cli.mjs", ...args], { stdio: "inherit", shell: process.platform === "win32", });Technical Analysis
The wrapper starts
./src/cli.mjsusing a path relative to the process's current working directory. It does not resolve the script relative to the installed Skill directory represented byimport.meta.url.Consequently, invoking the legitimate
skill.mjsfrom another working directory can cause Node.js to execute a differentsrc/cli.mjs. An attacker who can create files in that working directory can substitute arbitrary JavaScript without modifying the audited Skill package itself.This behavior is inconsistent with the documented entry point, which implies that execution should remain anchored to the Skill's base directory.
Attack Path
- An attacker identifies or controls a directory from which the Agent will invoke the Skill.
- The attacker creates a malicious file at
src/cli.mjsbeneath that directory. - The Agent invokes the genuine
skill.mjswhile the attacker-controlled directory is the current working directory. - The relative path
./src/cli.mjsresolves to the attacker's script. - Node.js executes the substituted script with the Agent process's privileges and inherited environment.
Impact Assessment
Successful exploitation provides arbitrary JavaScript execution under the operating-system account running the Agent. The malicious script inherits the wrapper's environment and may therefore access
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY, and other credentials available to the process.The attacker could use those credentials within their assigned IAM permissions, read or alter accessible local files, start additional processes, and make network requ ...[truncated 163 chars]
- Remediation
View remediation
Remediation Suggestions
Resolve
cli.mjsrelative to the wrapper's own location and invoke the current Node.js executable directly:js import path from "path"; import { fileURLToPath } from "url"; import { spawnSync } from "child_process"; const scriptPath = path.join( path.dirname(fileURLToPath(import.meta.url)), "cli.mjs" ); const result = spawnSync(process.execPath, [scriptPath, ...args], { stdio: "inherit", shell: false, }); if (result.error) { console.error("Failed to start CloudWatch CLI:", result.error.message); process.exit(1); } process.exit(result.status ?? 1);Additional hardening measures include:
- Do not depend on the caller's current working directory for executable paths.
- Use
process.execPathrather than resolvingnodethroughPATH. - Keep shell execution disabled on every platform.
- Treat failure to launch the child process as an error rather than returning exit status zero.
- Supply AWS credentials with only the required read-only CloudWatch permissions.
