T07 · Tool Hijacking and Spoofing
Error
- Location
- src/skill.mjs:4
- Finding
- Working-Directory Executable Hijacking in Skill Wrapper## Vulnerability Details **File Location**: `src/skill.mjs`, lines 4-7 **Vulnerability Type**: Working-directory script hijacking **Risk Level**: High ### Vulnerable Code ```js const result = spawnSync("node", ["./src/cli.mjs", ...args], { stdio: "inherit", shell: process.platform === "win32", }); ``` ### Technical Analysis The wrapper starts `./src/cli.mjs` using a path relative to the process's current working directory. It does not resolve the script relative to the installed Skill directory represented by `import.meta.url`. Consequently, invoking the legitimate `skill.mjs` from another working directory can cause Node.js to execute a different `src/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 1. An attacker identifies or controls a directory from which the Agent will invoke the Skill. 2. The attacker creates a malicious file at `src/cli.mjs` beneath that directory. 3. The Agent invokes the genuine `skill.mjs` while the attacker-controlled directory is the current working directory. 4. The relative path `./src/cli.mjs` resolves to the attacker's script. 5. 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
- ## Remediation Suggestions Resolve `cli.mjs` relative 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.execPath` rather than resolving `node` through `PATH`. - 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.
