mcp-server-kubernetes potential security issue in exec_in_pod tool
Description
MCP Server Kubernetes is an MCP Server that can connect to a Kubernetes cluster and manage it. Prior to 2.9.8, there is a security issue exists in the exec_in_pod tool of the mcp-server-kubernetes MCP Server. The tool accepts user-provided commands in both array and string formats. When a string format is provided, it is passed directly to shell interpretation (sh -c) without input validation, allowing shell metacharacters to be interpreted. This vulnerability can be exploited through direct command injection or indirect prompt injection attacks, where AI agents may execute commands without explicit user intent. This vulnerability is fixed in 2.9.8.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
mcp-server-kubernetesnpm | < 2.9.8 | 2.9.8 |
Affected products
1- Range: < 2.9.8
Patches
247d3136dd272Merge pull request #229 from Flux159/pr229
3 files changed · +136 −95
src/index.ts+2 −1 modified@@ -522,8 +522,9 @@ server.setRequestHandler( input as { name: string; namespace?: string; - command: string | string[]; + command: string[]; container?: string; + timeout?: number; context?: string; } );
src/tools/exec_in_pod.ts+39 −23 modified@@ -2,7 +2,10 @@ * Tool: exec_in_pod * Execute a command in a Kubernetes pod or container and return the output. * Uses the official Kubernetes client-node Exec API for native execution. - * Supports both string and array command formats, and optional container targeting. + * + * SECURITY: Only accepts commands as an array of strings. This prevents command + * injection attacks by executing directly without shell interpretation. + * Shell operators (pipes, redirects, etc.) are intentionally not supported. */ import * as k8s from "@kubernetes/client-node"; @@ -15,12 +18,12 @@ import { contextParameter, namespaceParameter } from "../models/common-parameter * Schema for exec_in_pod tool. * - name: Pod name * - namespace: Namespace (default: "default") - * - command: Command to execute (string or array of args) + * - command: Command to execute as array of strings (e.g. ["ls", "-la"]) * - container: (Optional) Container name */ export const execInPodSchema = { name: "exec_in_pod", - description: "Execute a command in a Kubernetes pod or container and return the output", + description: "Execute a command in a Kubernetes pod or container and return the output. Command must be an array of strings where the first element is the executable and remaining elements are arguments. This executes directly without shell interpretation for security.", inputSchema: { type: "object", properties: { @@ -30,20 +33,14 @@ export const execInPodSchema = { }, namespace: namespaceParameter, command: { - anyOf: [ - { type: "string" }, - { type: "array", items: { type: "string" } } - ], - description: "Command to execute in the pod (string or array of args)", + type: "array", + items: { type: "string" }, + description: "Command to execute as an array of strings (e.g. [\"ls\", \"-la\", \"/app\"]). First element is the executable, remaining are arguments. Shell operators like pipes, redirects, or command chaining are not supported - use explicit array format for security.", }, container: { type: "string", description: "Container name (required when pod has multiple containers)", }, - shell: { - type: "string", - description: "Shell to use for command execution (e.g. '/bin/sh', '/bin/bash'). If not provided, will use command as-is.", - }, timeout: { type: "number", description: "Timeout for command - 60000 milliseconds if not specified", @@ -58,31 +55,50 @@ export const execInPodSchema = { * Execute a command in a Kubernetes pod or container using the Kubernetes client-node Exec API. * Returns the stdout output as a text response. * Throws McpError on failure. + * + * SECURITY: Command must be an array of strings. This executes directly via the + * Kubernetes exec API without shell interpretation, preventing command injection. */ export async function execInPod( k8sManager: KubernetesManager, input: { name: string; namespace?: string; - command: string | string[]; + command: string[]; container?: string; - shell?: string; timeout?: number; context?: string; } ): Promise<{ content: { type: string; text: string }[] }> { const namespace = input.namespace || "default"; - // Convert command to array of strings for the Exec API - let commandArr: string[]; - if (Array.isArray(input.command)) { - commandArr = input.command; - } else { - // Always wrap string commands in a shell for correct parsing - const shell = input.shell || "/bin/sh"; - commandArr = [shell, "-c", input.command]; - console.log("[exec_in_pod] Using shell:", shell, "Command array:", commandArr); + + // Validate command is an array (defense in depth - schema should enforce this) + if (!Array.isArray(input.command)) { + throw new McpError( + ErrorCode.InvalidParams, + "Command must be an array of strings (e.g. [\"ls\", \"-la\"]). String commands are not supported for security reasons." + ); } + if (input.command.length === 0) { + throw new McpError( + ErrorCode.InvalidParams, + "Command array cannot be empty" + ); + } + + // Validate all elements are strings + for (let i = 0; i < input.command.length; i++) { + if (typeof input.command[i] !== "string") { + throw new McpError( + ErrorCode.InvalidParams, + `Command array element at index ${i} must be a string` + ); + } + } + + const commandArr = input.command; + // Prepare buffers to capture stdout and stderr let stdout = ""; let stderr = "";
tests/exec_in_pod.test.ts+95 −71 modified@@ -1,12 +1,14 @@ import { describe, test, expect, vi } from "vitest"; -import { execInPodSchema } from "../src/tools/exec_in_pod.js"; +import { execInPodSchema, execInPod } from "../src/tools/exec_in_pod.js"; +import { McpError } from "@modelcontextprotocol/sdk/types.js"; describe("exec_in_pod tool", () => { // Test the schema definition test("schema is properly defined", () => { expect(execInPodSchema).toBeDefined(); expect(execInPodSchema.name).toBe("exec_in_pod"); expect(execInPodSchema.description).toContain("Execute a command in a Kubernetes pod"); + expect(execInPodSchema.description).toContain("array of strings"); // Check input schema expect(execInPodSchema.inputSchema).toBeDefined(); @@ -16,87 +18,78 @@ describe("exec_in_pod tool", () => { expect(execInPodSchema.inputSchema.required).toContain("name"); expect(execInPodSchema.inputSchema.required).toContain("command"); - // Check for our newly added properties - expect(execInPodSchema.inputSchema.properties.shell).toBeDefined(); - expect(execInPodSchema.inputSchema.properties.shell.description).toContain("Shell to use"); + // Check command is array-only (no string support for security) + expect(execInPodSchema.inputSchema.properties.command.type).toBe("array"); + expect(execInPodSchema.inputSchema.properties.command.items.type).toBe("string"); + // Shell parameter should NOT exist (removed for security) + expect(execInPodSchema.inputSchema.properties.shell).toBeUndefined(); + + // Timeout should still exist expect(execInPodSchema.inputSchema.properties.timeout).toBeDefined(); expect(execInPodSchema.inputSchema.properties.timeout.description).toContain("Timeout for command"); expect(execInPodSchema.inputSchema.properties.timeout.type).toBe("number"); - - // Check command can be string or array - expect(execInPodSchema.inputSchema.properties.command.anyOf).toHaveLength(2); - expect(execInPodSchema.inputSchema.properties.command.anyOf[0].type).toBe("string"); - expect(execInPodSchema.inputSchema.properties.command.anyOf[1].type).toBe("array"); }); - // Test parameter handling - equivalent to kubectl exec command string handling - describe("command handling", () => { - // Simple test to verify command string/array handling - test("command parameter can be string or array", () => { - // Test string command - should wrap in shell (kubectl exec pod-name -- echo hello) - let commandArr = Array.isArray("echo hello") - ? "echo hello" - : ["/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/sh", "-c", "echo hello"]); - - // Test array command - should pass through as-is (kubectl exec pod-name -- echo hello) - commandArr = Array.isArray(["echo", "hello"]) - ? ["echo", "hello"] - : ["/bin/sh", "-c", ["echo", "hello"].join(" ")]; - expect(commandArr).toEqual(["echo", "hello"]); + // Test command handling - SECURITY: Only arrays are allowed + describe("command handling (security)", () => { + test("command must be an array of strings", () => { + // Array commands are valid + const validCommand = ["ls", "-la", "/app"]; + expect(Array.isArray(validCommand)).toBe(true); + expect(validCommand.every(arg => typeof arg === "string")).toBe(true); + }); + + test("array commands pass through without shell wrapping", () => { + // Array commands should be used as-is, not wrapped in shell + const command = ["echo", "hello", "world"]; + // The command array goes directly to K8s exec API + expect(command).toEqual(["echo", "hello", "world"]); + // NOT wrapped like ["/bin/sh", "-c", "echo hello world"] }); - // Test complex commands - test("handles complex command strings", () => { - // Test command with quotes (kubectl exec pod-name -- sh -c 'echo "hello world"') - let command = 'echo "hello world"'; - let commandArr = ["/bin/sh", "-c", command]; - expect(commandArr).toEqual(["/bin/sh", "-c", 'echo "hello world"']); - - // Test command with pipe (kubectl exec pod-name -- sh -c 'ls | grep file') - command = "ls | grep file"; - commandArr = ["/bin/sh", "-c", command]; - expect(commandArr).toEqual(["/bin/sh", "-c", "ls | grep file"]); - - // Test command with multiple statements (kubectl exec pod-name -- sh -c 'cd /tmp && ls') - command = "cd /tmp && ls"; - commandArr = ["/bin/sh", "-c", command]; - expect(commandArr).toEqual(["/bin/sh", "-c", "cd /tmp && ls"]); + test("command description explains security constraints", () => { + const desc = execInPodSchema.inputSchema.properties.command.description; + expect(desc).toContain("array of strings"); + expect(desc).toContain("security"); }); }); - // Test shell parameter handling - describe("shell parameter", () => { - test("shell parameter changes default shell", () => { - // Test with default shell (kubectl exec pod-name -- sh -c 'command') - let shell: string | undefined = undefined; - let commandArr = [shell || "/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/sh", "-c", "echo hello"]); - - // Test with bash shell (kubectl exec pod-name -- bash -c 'command') - shell = "/bin/bash"; - commandArr = [shell || "/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/bash", "-c", "echo hello"]); - - // Test with zsh shell (kubectl exec pod-name -- zsh -c 'command') - shell = "/bin/zsh"; - commandArr = [shell || "/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/zsh", "-c", "echo hello"]); + // Test validation logic (unit test the validation without K8s connection) + describe("input validation", () => { + // Create a mock k8sManager that throws before any K8s calls + const mockK8sManager = { + setCurrentContext: vi.fn(), + getKubeConfig: vi.fn(() => { + throw new Error("Should not reach K8s API in validation tests"); + }), + } as any; + + test("rejects non-array command", async () => { + await expect( + execInPod(mockK8sManager, { + name: "test-pod", + command: "echo hello" as any, // Force string to test validation + }) + ).rejects.toThrow("Command must be an array of strings"); }); - test("shell parameter not used with array commands", () => { - // Array commands should pass through regardless of shell - const command = ["echo", "hello"]; - const shell = "/bin/bash"; - - // With array commands, the shell should be ignored - if (Array.isArray(command)) { - expect(command).toEqual(["echo", "hello"]); - } else { - const shellCmd = [shell || "/bin/sh", "-c", command]; - expect(shellCmd).toEqual(["/bin/bash", "-c", "command-that-should-not-be-used"]); - } + test("rejects empty command array", async () => { + await expect( + execInPod(mockK8sManager, { + name: "test-pod", + command: [], + }) + ).rejects.toThrow("Command array cannot be empty"); + }); + + test("rejects command array with non-string elements", async () => { + await expect( + execInPod(mockK8sManager, { + name: "test-pod", + command: ["ls", 123 as any, "-la"], + }) + ).rejects.toThrow("must be a string"); }); }); @@ -108,12 +101,12 @@ describe("exec_in_pod tool", () => { return inputTimeout !== undefined ? inputTimeout : 60000; } - // Test with default timeout (kubectl exec has no built-in timeout) + // Test with default timeout let timeout: number | undefined = undefined; let timeoutMs = getTimeoutValue(timeout); expect(timeoutMs).toBe(60000); - // Test with custom timeout + // Test with custom timeout timeout = 30000; timeoutMs = getTimeoutValue(timeout); expect(timeoutMs).toBe(30000); @@ -238,4 +231,35 @@ describe("exec_in_pod tool", () => { expect(result.message).toContain("No output"); }); }); + + // Verify array format prevents shell interpretation + describe("exec in pod should only support string arrays", () => { + test("shell metacharacters in array elements are not interpreted", () => { + // When using array format, shell metacharacters are passed as literal strings + // to the executable, not interpreted by a shell + const command = ["echo", "hello; touch /tmp/pwned"]; + + // With array format, "hello; touch /tmp/pwned" is a single argument to echo + // It will literally print "hello; touch /tmp/pwned" not execute touch + expect(command[0]).toBe("echo"); + expect(command[1]).toBe("hello; touch /tmp/pwned"); // Literal string, not shell-interpreted + }); + + test("pipe operators in array elements are not interpreted", () => { + const command = ["cat", "/tmp/data | tee /tmp/output"]; + + // With array format, the pipe is part of the filename argument + // cat will try to open a file literally named "/tmp/data | tee /tmp/output" + expect(command[0]).toBe("cat"); + expect(command[1]).toContain("|"); // Literal pipe character + }); + + test("command substitution in array elements is not interpreted", () => { + const command = ["echo", "$(whoami)"]; + + // With array format, $(whoami) is printed literally + expect(command[0]).toBe("echo"); + expect(command[1]).toBe("$(whoami)"); // Not executed + }); + }); });
d091107ff92dUpdating exec_in_pod to only use string arrays.
3 files changed · +136 −95
src/index.ts+2 −1 modified@@ -522,8 +522,9 @@ server.setRequestHandler( input as { name: string; namespace?: string; - command: string | string[]; + command: string[]; container?: string; + timeout?: number; context?: string; } );
src/tools/exec_in_pod.ts+39 −23 modified@@ -2,7 +2,10 @@ * Tool: exec_in_pod * Execute a command in a Kubernetes pod or container and return the output. * Uses the official Kubernetes client-node Exec API for native execution. - * Supports both string and array command formats, and optional container targeting. + * + * SECURITY: Only accepts commands as an array of strings. This prevents command + * injection attacks by executing directly without shell interpretation. + * Shell operators (pipes, redirects, etc.) are intentionally not supported. */ import * as k8s from "@kubernetes/client-node"; @@ -15,12 +18,12 @@ import { contextParameter, namespaceParameter } from "../models/common-parameter * Schema for exec_in_pod tool. * - name: Pod name * - namespace: Namespace (default: "default") - * - command: Command to execute (string or array of args) + * - command: Command to execute as array of strings (e.g. ["ls", "-la"]) * - container: (Optional) Container name */ export const execInPodSchema = { name: "exec_in_pod", - description: "Execute a command in a Kubernetes pod or container and return the output", + description: "Execute a command in a Kubernetes pod or container and return the output. Command must be an array of strings where the first element is the executable and remaining elements are arguments. This executes directly without shell interpretation for security.", inputSchema: { type: "object", properties: { @@ -30,20 +33,14 @@ export const execInPodSchema = { }, namespace: namespaceParameter, command: { - anyOf: [ - { type: "string" }, - { type: "array", items: { type: "string" } } - ], - description: "Command to execute in the pod (string or array of args)", + type: "array", + items: { type: "string" }, + description: "Command to execute as an array of strings (e.g. [\"ls\", \"-la\", \"/app\"]). First element is the executable, remaining are arguments. Shell operators like pipes, redirects, or command chaining are not supported - use explicit array format for security.", }, container: { type: "string", description: "Container name (required when pod has multiple containers)", }, - shell: { - type: "string", - description: "Shell to use for command execution (e.g. '/bin/sh', '/bin/bash'). If not provided, will use command as-is.", - }, timeout: { type: "number", description: "Timeout for command - 60000 milliseconds if not specified", @@ -58,31 +55,50 @@ export const execInPodSchema = { * Execute a command in a Kubernetes pod or container using the Kubernetes client-node Exec API. * Returns the stdout output as a text response. * Throws McpError on failure. + * + * SECURITY: Command must be an array of strings. This executes directly via the + * Kubernetes exec API without shell interpretation, preventing command injection. */ export async function execInPod( k8sManager: KubernetesManager, input: { name: string; namespace?: string; - command: string | string[]; + command: string[]; container?: string; - shell?: string; timeout?: number; context?: string; } ): Promise<{ content: { type: string; text: string }[] }> { const namespace = input.namespace || "default"; - // Convert command to array of strings for the Exec API - let commandArr: string[]; - if (Array.isArray(input.command)) { - commandArr = input.command; - } else { - // Always wrap string commands in a shell for correct parsing - const shell = input.shell || "/bin/sh"; - commandArr = [shell, "-c", input.command]; - console.log("[exec_in_pod] Using shell:", shell, "Command array:", commandArr); + + // Validate command is an array (defense in depth - schema should enforce this) + if (!Array.isArray(input.command)) { + throw new McpError( + ErrorCode.InvalidParams, + "Command must be an array of strings (e.g. [\"ls\", \"-la\"]). String commands are not supported for security reasons." + ); } + if (input.command.length === 0) { + throw new McpError( + ErrorCode.InvalidParams, + "Command array cannot be empty" + ); + } + + // Validate all elements are strings + for (let i = 0; i < input.command.length; i++) { + if (typeof input.command[i] !== "string") { + throw new McpError( + ErrorCode.InvalidParams, + `Command array element at index ${i} must be a string` + ); + } + } + + const commandArr = input.command; + // Prepare buffers to capture stdout and stderr let stdout = ""; let stderr = "";
tests/exec_in_pod.test.ts+95 −71 modified@@ -1,12 +1,14 @@ import { describe, test, expect, vi } from "vitest"; -import { execInPodSchema } from "../src/tools/exec_in_pod.js"; +import { execInPodSchema, execInPod } from "../src/tools/exec_in_pod.js"; +import { McpError } from "@modelcontextprotocol/sdk/types.js"; describe("exec_in_pod tool", () => { // Test the schema definition test("schema is properly defined", () => { expect(execInPodSchema).toBeDefined(); expect(execInPodSchema.name).toBe("exec_in_pod"); expect(execInPodSchema.description).toContain("Execute a command in a Kubernetes pod"); + expect(execInPodSchema.description).toContain("array of strings"); // Check input schema expect(execInPodSchema.inputSchema).toBeDefined(); @@ -16,87 +18,78 @@ describe("exec_in_pod tool", () => { expect(execInPodSchema.inputSchema.required).toContain("name"); expect(execInPodSchema.inputSchema.required).toContain("command"); - // Check for our newly added properties - expect(execInPodSchema.inputSchema.properties.shell).toBeDefined(); - expect(execInPodSchema.inputSchema.properties.shell.description).toContain("Shell to use"); + // Check command is array-only (no string support for security) + expect(execInPodSchema.inputSchema.properties.command.type).toBe("array"); + expect(execInPodSchema.inputSchema.properties.command.items.type).toBe("string"); + // Shell parameter should NOT exist (removed for security) + expect(execInPodSchema.inputSchema.properties.shell).toBeUndefined(); + + // Timeout should still exist expect(execInPodSchema.inputSchema.properties.timeout).toBeDefined(); expect(execInPodSchema.inputSchema.properties.timeout.description).toContain("Timeout for command"); expect(execInPodSchema.inputSchema.properties.timeout.type).toBe("number"); - - // Check command can be string or array - expect(execInPodSchema.inputSchema.properties.command.anyOf).toHaveLength(2); - expect(execInPodSchema.inputSchema.properties.command.anyOf[0].type).toBe("string"); - expect(execInPodSchema.inputSchema.properties.command.anyOf[1].type).toBe("array"); }); - // Test parameter handling - equivalent to kubectl exec command string handling - describe("command handling", () => { - // Simple test to verify command string/array handling - test("command parameter can be string or array", () => { - // Test string command - should wrap in shell (kubectl exec pod-name -- echo hello) - let commandArr = Array.isArray("echo hello") - ? "echo hello" - : ["/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/sh", "-c", "echo hello"]); - - // Test array command - should pass through as-is (kubectl exec pod-name -- echo hello) - commandArr = Array.isArray(["echo", "hello"]) - ? ["echo", "hello"] - : ["/bin/sh", "-c", ["echo", "hello"].join(" ")]; - expect(commandArr).toEqual(["echo", "hello"]); + // Test command handling - SECURITY: Only arrays are allowed + describe("command handling (security)", () => { + test("command must be an array of strings", () => { + // Array commands are valid + const validCommand = ["ls", "-la", "/app"]; + expect(Array.isArray(validCommand)).toBe(true); + expect(validCommand.every(arg => typeof arg === "string")).toBe(true); + }); + + test("array commands pass through without shell wrapping", () => { + // Array commands should be used as-is, not wrapped in shell + const command = ["echo", "hello", "world"]; + // The command array goes directly to K8s exec API + expect(command).toEqual(["echo", "hello", "world"]); + // NOT wrapped like ["/bin/sh", "-c", "echo hello world"] }); - // Test complex commands - test("handles complex command strings", () => { - // Test command with quotes (kubectl exec pod-name -- sh -c 'echo "hello world"') - let command = 'echo "hello world"'; - let commandArr = ["/bin/sh", "-c", command]; - expect(commandArr).toEqual(["/bin/sh", "-c", 'echo "hello world"']); - - // Test command with pipe (kubectl exec pod-name -- sh -c 'ls | grep file') - command = "ls | grep file"; - commandArr = ["/bin/sh", "-c", command]; - expect(commandArr).toEqual(["/bin/sh", "-c", "ls | grep file"]); - - // Test command with multiple statements (kubectl exec pod-name -- sh -c 'cd /tmp && ls') - command = "cd /tmp && ls"; - commandArr = ["/bin/sh", "-c", command]; - expect(commandArr).toEqual(["/bin/sh", "-c", "cd /tmp && ls"]); + test("command description explains security constraints", () => { + const desc = execInPodSchema.inputSchema.properties.command.description; + expect(desc).toContain("array of strings"); + expect(desc).toContain("security"); }); }); - // Test shell parameter handling - describe("shell parameter", () => { - test("shell parameter changes default shell", () => { - // Test with default shell (kubectl exec pod-name -- sh -c 'command') - let shell: string | undefined = undefined; - let commandArr = [shell || "/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/sh", "-c", "echo hello"]); - - // Test with bash shell (kubectl exec pod-name -- bash -c 'command') - shell = "/bin/bash"; - commandArr = [shell || "/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/bash", "-c", "echo hello"]); - - // Test with zsh shell (kubectl exec pod-name -- zsh -c 'command') - shell = "/bin/zsh"; - commandArr = [shell || "/bin/sh", "-c", "echo hello"]; - expect(commandArr).toEqual(["/bin/zsh", "-c", "echo hello"]); + // Test validation logic (unit test the validation without K8s connection) + describe("input validation", () => { + // Create a mock k8sManager that throws before any K8s calls + const mockK8sManager = { + setCurrentContext: vi.fn(), + getKubeConfig: vi.fn(() => { + throw new Error("Should not reach K8s API in validation tests"); + }), + } as any; + + test("rejects non-array command", async () => { + await expect( + execInPod(mockK8sManager, { + name: "test-pod", + command: "echo hello" as any, // Force string to test validation + }) + ).rejects.toThrow("Command must be an array of strings"); }); - test("shell parameter not used with array commands", () => { - // Array commands should pass through regardless of shell - const command = ["echo", "hello"]; - const shell = "/bin/bash"; - - // With array commands, the shell should be ignored - if (Array.isArray(command)) { - expect(command).toEqual(["echo", "hello"]); - } else { - const shellCmd = [shell || "/bin/sh", "-c", command]; - expect(shellCmd).toEqual(["/bin/bash", "-c", "command-that-should-not-be-used"]); - } + test("rejects empty command array", async () => { + await expect( + execInPod(mockK8sManager, { + name: "test-pod", + command: [], + }) + ).rejects.toThrow("Command array cannot be empty"); + }); + + test("rejects command array with non-string elements", async () => { + await expect( + execInPod(mockK8sManager, { + name: "test-pod", + command: ["ls", 123 as any, "-la"], + }) + ).rejects.toThrow("must be a string"); }); }); @@ -108,12 +101,12 @@ describe("exec_in_pod tool", () => { return inputTimeout !== undefined ? inputTimeout : 60000; } - // Test with default timeout (kubectl exec has no built-in timeout) + // Test with default timeout let timeout: number | undefined = undefined; let timeoutMs = getTimeoutValue(timeout); expect(timeoutMs).toBe(60000); - // Test with custom timeout + // Test with custom timeout timeout = 30000; timeoutMs = getTimeoutValue(timeout); expect(timeoutMs).toBe(30000); @@ -238,4 +231,35 @@ describe("exec_in_pod tool", () => { expect(result.message).toContain("No output"); }); }); + + // Verify array format prevents shell interpretation + describe("exec in pod should only support string arrays", () => { + test("shell metacharacters in array elements are not interpreted", () => { + // When using array format, shell metacharacters are passed as literal strings + // to the executable, not interpreted by a shell + const command = ["echo", "hello; touch /tmp/pwned"]; + + // With array format, "hello; touch /tmp/pwned" is a single argument to echo + // It will literally print "hello; touch /tmp/pwned" not execute touch + expect(command[0]).toBe("echo"); + expect(command[1]).toBe("hello; touch /tmp/pwned"); // Literal string, not shell-interpreted + }); + + test("pipe operators in array elements are not interpreted", () => { + const command = ["cat", "/tmp/data | tee /tmp/output"]; + + // With array format, the pipe is part of the filename argument + // cat will try to open a file literally named "/tmp/data | tee /tmp/output" + expect(command[0]).toBe("cat"); + expect(command[1]).toContain("|"); // Literal pipe character + }); + + test("command substitution in array elements is not interpreted", () => { + const command = ["echo", "$(whoami)"]; + + // With array format, $(whoami) is printed literally + expect(command[0]).toBe("echo"); + expect(command[1]).toBe("$(whoami)"); // Not executed + }); + }); });
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
5- github.com/advisories/GHSA-wvxp-jp4w-w8wgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-66404ghsaADVISORY
- github.com/Flux159/mcp-server-kubernetes/commit/47d3136dd272c947464524f11f47bb519814698eghsaWEB
- github.com/Flux159/mcp-server-kubernetes/commit/d091107ff92d9ffad1b3c295092f142d6578c48bghsax_refsource_MISCWEB
- github.com/Flux159/mcp-server-kubernetes/security/advisories/GHSA-wvxp-jp4w-w8wgghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.