Jun 15, 2026·9 min read·23 visits
Unsanitized input interpolation in the AWS CDK NodejsFunction bundling component allows unauthenticated local command execution during infrastructure synthesis (cdk synth).
A critical supply-chain OS command injection vulnerability exists in the NodejsFunction local bundling pipeline within the AWS Cloud Development Kit (CDK) library (aws-cdk-lib) before version 2.245.0 (and before 2.246.0 on Windows systems). The vulnerability allows a threat actor who can control any of several bundling properties (externalModules, define, loader, inject, or esbuildArgs) to execute arbitrary operating system commands on the host machine running the CDK compilation or deployment toolchain (e.g., during cdk synth, cdk deploy, or cdk diff).
The AWS Cloud Development Kit (CDK) is an open-source software development framework to define cloud infrastructure in code and provision it through AWS CloudFormation. Within this framework, the NodejsFunction construct (under the @aws-cdk/aws-lambda-nodejs package or aws-cdk-lib/aws-lambda-nodejs) abstracts the process of compiling, bundling, and packaging JavaScript or TypeScript code for AWS Lambda. Under the hood, this construct leverages esbuild to compile target source entries, bundle associated dependencies, and output an archive optimized for cloud deployment. This pipeline executes automatically during the synthesis phase, which converts high-level programming language code into CloudFormation templates.
A critical supply-chain OS command injection vulnerability (classified as CWE-78) exists in the local bundling implementation of this construct. An attacker who can control specific configuration parameters can inject malicious OS shell metacharacters. Because these parameters are subsequently passed directly to the local shell environment during compilation, the payload executes on the host workstation or automated build runner. This execution operates with the execution privileges of the user initiating the synthesis process, typically a developer or a highly privileged continuous integration (CI) service.
The attack surface is particularly severe because the vulnerability manifests during infrastructure synthesis rather than deployment or runtime. Standard client-side secure-install configurations, such as utilizing the --ignore-scripts flag during package installation, fail to mitigate this threat because the code executes within standard TypeScript code paths rather than lifecycle hooks. Consequently, this vulnerability opens up significant supply-chain pathways. Threat actors can exploit the vulnerability by publishing malicious packages containing custom wrapper constructs, or by submitting pull requests containing modified bundling configurations to open-source repositories.
The vulnerability stems from the direct concatenation of user-supplied bundling parameters into an operating system shell command. When NodejsFunction utilizes local bundling, the AWS CDK CLI runtime attempts to invoke esbuild locally rather than spawning a Docker container. The underlying logic builds a shell command dynamically using an array of arguments representing various compiler flags and values. Unescaped configuration parameters are directly interpolated into this argument array.
Specifically, the vulnerable code in bundling.ts processes configuration fields including externalModules, loader, define, inject, and esbuildArgs. These fields allow developers to customize the behavior of the compilation process by specifying external dependencies, file loaders, preprocessor definitions, and raw arguments. The code constructs an array of strings representing the final command line, joining the array with spaces to form a single execution string. This raw string is then passed to a process execution wrapper that spawns /bin/bash -c on POSIX systems or cmd.exe /c on Windows systems.
Because the runtime performs no validation, escaping, or sanitization on these configuration fields, shell metacharacters such as &, ;, |, or backticks passed within these strings act as command separators. When the shell interprets the compiled execution string, it reads these characters as instructions to split the commands. This results in the sequential or parallel execution of the original compiler call and the injected attacker payload. The command executes under the same environment context and privileges as the CDK CLI process.
To address this vulnerability, the AWS CDK engineering team released a sequence of security updates. The primary fix, implemented in Pull Request #37292, completely refactors how local execution occurs. The vulnerability mitigation centers on migrating from shell-based command string execution to direct process spawning. By passing an array of arguments to Node's child_process.spawnSync with { shell: false }, the operating system loads the executable binary directly without executing a shell interpreter. This ensures that command line arguments are passed as discrete strings to the target program's execution vector rather than parsed by a command shell, preventing command injection.
// Pre-Patch Code (aws-lambda-nodejs/lib/bundling.ts)
// Dynamic assembly of a single CLI command string via interpolation
const esbuildCommand: string[] = [
options.esbuildRunner,
'--bundle', `"${relativeEntryPath}"`,
`--target=${this.props.target ?? toTarget(scope, this.props.runtime)}`,
'--platform=node',
...this.externals.map(external => `--external:${external}`),
...loaders.map(([ext, name]) => `--loader:${ext}=${name}`),
...defines.map(([key, value]) => `--define:${key}=${JSON.stringify(value)}`),
...this.props.inject ? this.props.inject.map(i => `--inject:"${i}"`) : [],
...this.props.esbuildArgs ? [toCliArgs(this.props.esbuildArgs)] : [],
];
const localCommand = esbuildCommand.join(' ');
exec(
osPlatform === 'win32' ? 'cmd' : 'bash',
[osPlatform === 'win32' ? '/c' : '-c', localCommand],
{ env: { ...process.env }, cwd }
);// Patched Code (aws-lambda-nodejs/lib/bundling.ts)
// Transitioned to structured BundlingStep types avoiding direct shell execution
type BundlingStep =
| { type: 'shell'; commands: string[] }
| { type: 'spawn'; command: string[]; cwd?: string }
| { type: 'callback'; operation: () => void };
// Execution of the 'spawn' step bypasses the shell entirely
if (step.type === 'spawn') {
const [command, ...args] = step.command;
const result = spawnSync(command, args, {
cwd: step.cwd ?? cwd,
env: { ...process.env, ...environment },
stdio: ['ignore', 'pipe', 'pipe'],
});
if (result.status !== 0) {
throw new Error(`Command failed with status ${result.status}`);
}
}A secondary patch, Pull Request #37412, was introduced to resolve an operating system regression. On Windows systems running Node.js v22 or higher, executing .cmd or .bat shims directly via spawnSync without shell wrapping triggers an OS-level EINVAL error. To resolve this while preventing command injection, the patch routes execution through powershell.exe but strictly escapes all arguments using a new powershellEscape utility. This ensures arguments are treated strictly as string literals inside the PowerShell environment.
// PowerShell Escaping Utility in PR #37412
function powershellEscape(arg: string): string {
// Escape single quotes inside single-quoted strings by doubling them
return "'" + arg.replace(/'/g, "''") + "'";
}
if (osPlatform === 'win32') {
// Route via powershell and join arguments using the call operator
exec('powershell.exe', [
'-NoProfile',
'-Command',
`& ${step.command.map(powershellEscape).join(' ')}`
], {
cwd: step.cwd ?? cwd,
env: { ...process.env, ...environment }
});
}Exploitation of CVE-2026-11417 requires an attacker to inject a shell metacharacter into one of the configurable properties of the NodejsFunction bundling properties. This control can be achieved via a direct modification in a pull request to a target repository, or by publishing a malicious npm package containing a custom CDK construct wrapper that inherits from NodejsFunction and injects the payload under the hood. The target system must then perform infrastructure synthesis.
To demonstrate this behavior, a simple proof of concept can be established by configuring a stack containing a single NodejsFunction. By manipulating the externalModules parameter within the bundling configuration, an attacker can append a command separator and an arbitrary operating system command. When cdk synth is executed, the injection triggers immediately.
import * as cdk from 'aws-cdk-lib';
import { Stack } from 'aws-cdk-lib';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import * as path from 'path';
export class VulnerableStack extends Stack {
constructor(scope: cdk.App, id: string) {
super(scope, id);
new NodejsFunction(this, 'ExploitTarget', {
entry: path.join(__dirname, 'lambda', 'handler.ts'),
runtime: Runtime.NODEJS_20_X,
bundling: {
// Injection payload uses the '&' shell metacharacter
// This runs the shell command immediately following esbuild invocation
externalModules: ['aws-sdk & echo "EXPLOIT_SUCCESSFUL" > /tmp/pwned.txt'],
},
});
}
}Executing cdk synth on a system running an affected version of aws-cdk-lib results in the execution of the injected command block. The shell separates the executing processes, running the compiler and then executing the second command. This creates the file /tmp/pwned.txt on the host, demonstrating successful local remote code execution.
The impact of this command injection vulnerability is substantial due to its positioning in the software supply chain. While standard runtime vulnerabilities threaten the production environment, a synthesis-time vulnerability targets the development workstation and the deployment pipelines directly. An attacker who successfully exploits this flaw can execute arbitrary commands with the privileges of the active developer or the continuous integration (CI/CD) runner, gaining complete compromise over the underlying operating system environment.
In typical modern cloud deployments, developer machines and CI/CD pipelines hold highly sensitive credentials, such as active AWS session tokens, long-lived AWS IAM access keys, SSH keys, and access tokens for internal code repositories. Gaining execution on these runners allows an attacker to access environment variables, retrieve stored configuration secrets, and exfiltrate credentials to an external server. Because the execution runs within a trusted build phase, the outbound network requests generated by the payload might bypass egress firewall restrictions configured for production environments.
Additionally, access to the synthesis environment allows an attacker to manipulate the generated CloudFormation templates. This permits subtle modifications to infrastructure definitions, such as altering security group configurations to expose database ports, modifying IAM policy definitions to grant excessive permissions, or injecting malicious backdoors into the built Lambda deployment packages. The vulnerability therefore bridges local workstation compromise to complete cloud architecture compromise.
The definitive mitigation for this vulnerability is upgrading the AWS CDK library to a patched version. For applications running on Linux or macOS workstations, upgrade aws-cdk-lib to version 2.245.0 or higher. For applications built on Windows systems, upgrade aws-cdk-lib to version 2.246.0 or higher to resolve compatibility issues with direct process spawning on Node.js v22+ environments.
In environments where upgrading the library is not immediately possible, organizations can enforce defensive controls to mitigate the risk. The vulnerability can be neutralized by forcing the use of Docker-based bundling rather than local bundling. This is achieved by ensuring that Docker is running and available to the CDK CLI, or by modifying the construct configuration to explicitly utilize containerized environments. When bundling runs inside an isolated Docker container, the command injection is constrained to the container workspace, preventing access to the host workstation's file system and environmental secrets.
Furthermore, organizations should restrict the permissions allocated to CI/CD runners during the synthesis phase. The generation of CloudFormation templates via cdk synth is a purely local compilation task that does not require direct access to active AWS credentials or cloud infrastructure endpoints. Separating the synthesis step into an isolated, unprivileged build phase that lacks cloud deployment credentials significantly limits the blast radius of a potential exploitation attempt. Implement static analysis and linting rules to flag or reject pull requests that modify bundling properties inside CDK infrastructure code.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
aws-cdk-lib AWS | < 2.245.0 | 2.245.0 |
aws-cdk-lib (Windows) AWS | < 2.246.0 | 2.246.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-78 |
| Attack Vector | Local |
| CVSS Score | 7.3 (CVSS:3.1) |
| EPSS Score | 0.00657 (Percentile: 46.42%) |
| Impact | Unauthenticated OS Command Execution |
| Exploit Status | Proof of Concept / Public Exploit Code Available |
| CISA KEV Status | Not Listed |
The software constructs an OS command using externally-influenced input, but it does not neutralize or incorrectly neutralizes special elements that can modify the intended OS command when it is sent to a downstream component.
An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.
CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.
CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.
The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.
CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.
An authenticated remote code execution vulnerability exists in NotrinosERP (versions up to and including 1.0.0) within the Human Resource Management (HRM) module. Users with employee management permissions can upload arbitrary file types, including PHP scripts, which are written directly to a web-accessible directory. This allows for arbitrary code execution in the context of the web-server user.