CVE-2026-5602
Description
A vulnerability was determined in Nor2-io heim-mcp up to 0.1.3. Impacted is the function registerTools of the file src/tools.ts of the component new_heim_application/deploy_heim_application/deploy_heim_application_to_cloud. This manipulation causes os command injection. The attack requires local access. The exploit has been publicly disclosed and may be utilized. Patch name: c321d8af25f77668781e6ccb43a1336f9185df37. It is suggested to install a patch to address this issue. The vendor was contacted early, responded in a very professional manner and quickly released a fixed version of the affected product.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
@nor2/heim-mcpnpm | <= 0.1.3 | — |
Affected products
1Patches
1c321d8af25f7Merge pull request #2 from 123mutouren321414/fix-command-injection
1 file changed · +42 −29
src/tools.ts+42 −29 modified@@ -1,5 +1,5 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { exec } from "child_process"; +import { execFile } from "child_process"; import { z } from "zod"; import util from "util"; @@ -59,23 +59,32 @@ export function registerTools(server: McpServer) { }, }, async (request) => { - const execPromise = util.promisify(exec); + const execFilePromise = util.promisify(execFile); try { - const { stdout, stderr } = await execPromise( - `heim new --path ${request.path} --spec ${ - request.openApiPath - } --name ${request.name} --version ${request.version} --language ${ - request.language - } --base-path ${request.basePath} ${ - request.overwrite ? "--force" : "" - }` - ); + const args = [ + "new", + "--path", request.path, + "--spec", request.openApiPath, + "--name", request.name, + "--version", request.version, + "--language", request.language, + "--base-path", request.basePath]; + if (request.overwrite) args.push("--force"); + const { stdout, stderr } = await execFilePromise("heim", args); - const output2 = await execPromise( + const output2 = request.language == "rust" - ? `cargo build --manifest-path ${request.path}/${request.name}/Cargo.toml --target wasm32-wasip2` - : `dotnet build ${request.path}/${request.name}/${request.name}.csproj` - ); + ? await execFilePromise("cargo", [ + "build", + "--manifest-path", + `${request.path}/${request.name}/Cargo.toml`, + "--target", + "wasm32-wasip2", + ]) + : await execFilePromise("dotnet", [ + "build", + `${request.path}/${request.name}/${request.name}.csproj`, + ]); return { content: [ @@ -115,11 +124,12 @@ export function registerTools(server: McpServer) { }, }, async (request) => { - const execPromise = util.promisify(exec); + const execFilePromise = util.promisify(execFile); try { - const { stdout, stderr } = await execPromise( - `heim deploy ${request.path}` - ); + const args = ["deploy"]; + if (request.path) args.push(request.path); + + const { stdout, stderr } = await execFilePromise("heim", args); return { content: [ { @@ -158,12 +168,14 @@ export function registerTools(server: McpServer) { }, }, async (request) => { - const execPromise = util.promisify(exec); + const execFilePromise = util.promisify(execFile); try { //TODO: Update to use org and project when a user has multiple orgs and projects - const { stdout, stderr } = await execPromise( - `heim deploy ${request.path} --cloud` - ); + const args = ["deploy"]; + if (request.path) args.push(request.path); + args.push("--cloud"); + + const { stdout, stderr } = await execFilePromise("heim", args); return { content: [ { @@ -195,9 +207,9 @@ export function registerTools(server: McpServer) { openWorldHint: false, }, async () => { - const execPromise = util.promisify(exec); + const execFilePromise = util.promisify(execFile); try { - const { stdout, stderr } = await execPromise("heim start"); + const { stdout, stderr } = await execFilePromise("heim", ["start"]); return { content: [ { @@ -227,9 +239,9 @@ export function registerTools(server: McpServer) { openWorldHint: false, }, async () => { - const execPromise = util.promisify(exec); + const execFilePromise = util.promisify(execFile); try { - const { stdout, stderr } = await execPromise("heim clear --force"); + const { stdout, stderr } = await execFilePromise("heim", ["clear", "--force"]); return { content: [ { @@ -259,9 +271,9 @@ export function registerTools(server: McpServer) { openWorldHint: false, }, async () => { - const execPromise = util.promisify(exec); + const execFilePromise = util.promisify(execFile); try { - const { stdout, stderr } = await execPromise("heim update"); + const { stdout, stderr } = await execFilePromise("heim", ["update"]); return { content: [ { @@ -279,3 +291,4 @@ export function registerTools(server: McpServer) { } ); } +
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-wx4p-jr66-jfp9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-5602ghsaADVISORY
- github.com/Nor2-io/heim-mcp/commit/c321d8af25f77668781e6ccb43a1336f9185df37nvdWEB
- github.com/Nor2-io/heim-mcp/issues/1nvdWEB
- github.com/Nor2-io/heim-mcp/pull/2nvdWEB
- vuldb.com/submit/784862nvdWEB
- vuldb.com/vuln/355394nvdWEB
- vuldb.com/vuln/355394/ctinvdWEB
News mentions
0No linked articles in our index yet.