
مثال Seal Security — تطبيق pip ضعيف (PyYAML CVE-2020-14343) تمت معالجته إلى إصدارات sealed؛ تكامل GitHub Actions + Jenkins
تطبيق Flask بسيط، وهشّ عمدًا، يُستخدم لتوضيح كيفية معالجة Seal Security لثغرة CVE معروفة، من البداية إلى النهاية، عبر استبدال اعتمادية هشّة بنسخة مُختومة (sealed) — وهي نسخة مرجوع إليها الإصلاح الأمني (backported) وتعمل كبديل مباشر (drop‑in) — دون أي تغيير في المتطلبات المُعلَنة أو في الكود الخاص بك.
صُمم ليكون اختبار دخان شاملًا (front‑to‑back) لواجهة Seal CLI في CI/CD: شغّل التطبيق، وأطلق استغلالًا حقيقيًا، وشغّل Seal، ولاحظ كيف يُحجب الاستغلال نفسه.
| النظام البيئي | Python / pip |
| الحزمة الهشّة | PyYAML==5.1 |
| CVE | CVE‑2020‑14343 — إلغاء تسلسل yaml.load / FullLoader ← تنفيذ تعسّفي للكود |
| النسخة المختومة (المُصحَّحة) | pyyaml 5.1+sp1 من سجل PyPI الخاص بـ Seal |
| التكامل | واجهة Seal CLI كخطوة بناء واحدة — معروضة لكل من GitHub Actions و Jenkins |
تأخذ صفحة الترحيب قيمة name وتحلّلها عبر المحمّل الافتراضي في PyYAML:
parsed = yaml.load(name) # PyYAML 5.1 → unsafe FullLoader (CVE-2020-14343)
في PyYAML 5.1، يستخدم yaml.load() دون تحديد SafeLoader صريح المحمّل FullLoader، الذي يمكنه إنشاء كائنات Python تعسفية من مدخلات غير موثوقة. يرسل المهاجم حمولة YAML تُنفّذ كود Python تعسفيًا على الخادم.
طلب عادي
/?name=alice → Welcome, alice!
طلب الاستغلال — مرِّر حمولة YAML هذه كقيمة name (مشفّرة URL مسبقًا في سجلات سير العمل):
!!python/object/apply:tuple [!!python/object/apply:map [!!python:name:eval , ["__import__('subprocess').check_output(['id']).decode()"]]]
يقوم PyYAML الهش بإلغاء تسلسل الحمولة وتنفيذها، ويعرض التطبيق صفحة «You've been pwned»، ثم يُقتل الخادم (بعد ثوانٍ قليلة، كي تُعرض الصفحة أولًا). أعد التحميل وسيختفي التطبيق — عبر ngrok سترى صفحة «endpoint offline».
.
├── app.py # the vulnerable Flask app
├── requirements.txt # declares PyYAML==5.1
├── Jenkinsfile # example Jenkins (Groovy) pipeline with the Seal stage
└── .github/workflows/
├── build-and-run.yml # run + expose the app for browser testing
└── seal-security.yml # run Seal remediation, then start the app
Seal هي خدمة SaaS تستضيفها Seal — لا يُثبَّت أي شيء داخل بيئتك، وكل حركة المرور هي HTTPS صادرة على TCP 443 فقط. لتشغيل المعالجة تحتاج إلى:
| السر / الاعتماد | الغرض منه | مكانه |
|---|
عيّن هذه في Settings → Secrets and variables → Actions (على GitHub) أو Manage Jenkins → Credentials (في Jenkins). لا تدفع الرموز إلى المستودع أبدًا.
أضف مضيفات Seal هذه إلى القائمة البيضاء للاتصالات الصادرة على المنفذ 443:
app.sealsecurity.io, authorization.sealsecurity.io, cli.sealsecurity.io، ولحزم pip المختومة — pypi.sealsecurity.io. يُنزَّل ملف CLI الثنائي من github.com / objects.githubusercontent.com.
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python app.py # → http://localhost:5000
افتح http://localhost:5000/?name=alice (يعمل)، ثم أرسل حمولة الاستغلال أعلاه كقيمة name — يعرض التطبيق «You've been pwned» ويُقتل الخادم بعد ثوانٍ قليلة.
تعمل واجهة Seal CLI كخطوة إضافية واحدة، بعد pip install وقبل التغليف. تفحص الاعتماديات المُحلَّلة وتعيد كتابة الاعتماديات الهشّة إلى نسخها المختومة، باستخدام وضع الإصلاح عن بُعد (remote) (تُدار السياسة مركزيًا في واجهة Seal).
يستخدم seal-community/cli-action:
- uses: seal-community/cli-action@latest
with:
mode: fix
fix_mode: remote
token: ${{ secrets.SEAL_TOKEN }}
target: requirements.txt # the manifest for this ecosystem
شغّله عبر Actions → «Seal Security Remediation» → Run workflow. انظر .github/workflows/seal-security.yml.
مرحلة واحدة مُضافة، بعد التثبيت وقبل التغليف. انظر Jenkinsfile:
stage('Seal') {
steps {
sh '''
curl -fsSL https://github.com/seal-community/cli/releases/download/latest/seal-linux-amd64-latest -o seal
chmod +x seal
./seal fix --mode remote "$SEAL_MANIFEST" # SEAL_MANIFEST=requirements.txt
'''
}
}
يأتي SEAL_TOKEN من اعتماد Jenkins seal-token؛ اضبط SEAL_PROJECT على معرّف مشروعك في Seal.
بعد seal fix، تتحلّل الاعتمادية الهشّة إلى بناء مختوم من سجل PyPI الخاص بـ Seal — نفس الحزمة مع إرجاع الإصلاح الأمني إليها:
| الاعتمادية | قبل | بعد (مختومة) |
|---|---|---|
| PyYAML | 5.1 | 5.1+sp1 |
النسخة المختومة هي نفس الحزمة مع الإصلاح الأمني المرجوع إليها — بديل مباشر (drop‑in)، دون تغييرات في الكود ودون ترقية للنسخة الرئيسية.
أعد تشغيل الاستغلال ضد التطبيق المُعالَج. يرفض PyYAML المختوم إنشاء الكائنات الضارة، لذا يرفع yaml.load استثناءً بدلًا من تنفيذ الحمولة، ويستجيب التطبيق بـ «Invalid input — payload rejected.» وما تزال الأسماء العادية تعمل.
seal fix إلى ملف البيان المحدد — requirements.txt بالنسبة إلى pip. بالنسبة إلى مستودع يحتوي عدة ملفات بيان/قفل، شغّل seal fix مرة واحدة لكل ملف بيان.هذا هو التكامل بأكمله — مرحلة واحدة، اتصالات صادرة فقط، دون أي تغييرات على كود التطبيق.
| رمز Seal | مصادقة واجهة Seal CLI | سر GitHub Actions SEAL_TOKEN / اعتماد Jenkins «نص سري» seal-token |
| رمز ngrok (اختياري) | كشف التطبيق قيد التشغيل لمتصفح للاختبار | سر GitHub Actions NGROK_TOKEN |