
يوفر هذا المستودع معالجة أمنية شاملة لثغرات حرمان الخدمة وتخصيص الموارد دون حدود أو تقييد التي تم الإبلاغ عنها في CVE-2025-52999 وGHSA-2m67-wjpj-xhg9 وsonatype-2022-6438، مع الحفاظ على التوافق الكامل مع jackson‑core 2.13.5.
يحتوي هذا الفرع (2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9) على معالجة أمنية شاملة لثغرات حجب الخدمة (DoS) واستنزاف الموارد دون حدود أو تقييد التي تستهدف jackson-core 2.13.5. يقدّم واجهة StreamReadConstraints API — المتوافقة مع الواجهة المقدمة في jackson-core 2.15.0 ولكن مع توسيع تغطية المحلّل وإضافات حماية إضافية من نواقل الهجوم — لمعالجة هجوم استنزاف عمق التداخل (CVE-2025-52999)، واستنزاف الموارد دون حدود أو تقييد (SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924)، وتجاوز قيد طول المستند (SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9)، وهجوم استنزاف طول الرمز الرقمي (Sonatype-2022-6438) مع بقائه متوافقًا مع سطح واجهة API العامة لإصدار jackson-core 2.13.5.
| الفرع | الثغرات التي تمت معالجتها |
|---|---|
2.13.5-CVE-2025-52999-sonatype-2022-6438 | CVE-2025-52999, Sonatype-2022-6438, SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 |
2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 | جميع ما سبق + GHSA-2m67-wjpj-xhg9 (تجاوز قيد طول المستند) |
الفرع الأصلي (2.13.5-CVE-2025-52999-sonatype-2022-6438) يعالج ثلاث ثغرات
وقد تم الحفاظ عليه على الاستضافة البعيدة sasso. يوسّع هذا الفرع ما سبق بالمعالجة الإضافية لـ
GHSA-2m67-wjpj-xhg9،
والذي يفرض maxDocumentLength عبر جميع مسارات المحلّل.
إدخال NVD
الوصف الرسمي من NVD
jackson-core يحتوي على التجريدات الأساسية منخفضة المستوى ("التدفقية") للمحلّل والمولّد المستخدمة من قِبل معالج بيانات Jackson. في الإصدارات السابقة لـ 2.15.0، إذا قام المستخدم بتحليل ملف إدخال يحتوي على بيانات متداخلة بعمق كبير، فقد ينتهي الأمر بـ Jackson برمي
StackOverflowErrorإذا كان العمق كبيرًا بشكل خاص. يحتوي jackson-core 2.15.0 على حد قابل للتهيئة لمدى العمق الذي سيتنقّله Jackson داخل مستند الإدخال، مع قيمة افتراضية تسمح بعمق 1,000. سيقوم jackson-core برميStreamConstraintsExceptionإذا تم بلوغ الحد. كما يستفيد jackson-databind من هذا التغيير لأنه يستخدم jackson-core لتحليل مدخلات JSON. كحل بديل، يجب على المستخدمين تجنب تحليل ملفات الإدخال من مصادر غير موثوقة.
الحل المؤقت: تجنب تحليل مدخلات JSON من مصادر غير موثوقة حتى يتم نشر الإصدار المعالَج.
السبب الجذري: قبل 2.15.0، لم يفرض JsonParser أي حد على مدى عمق تداخل مستند JSON.
كل رمز [ لمصفوفة أو { لكائن كان يتسبب في قيام JsonReadContext.createChildArrayContext() /
createChildObjectContext() بتخصيص عقدة سياق جديدة على الكومة وزيادة سلسلة مراجع.
يمكن للمهاجم صياغة مستند يحتوي على عشرات الآلاف من المستويات المتداخلة، مما يتسبب في استنفاد
الجهاز الافتراضي Java لذاكرة مكدس الخيط أو ذاكرة الكومة.
مسار الكود المعرّض:
يتم الوصول إلى نفس الفحص المفقود عبر كل من تطبيقات المحلّل الأربعة:``` JsonParser.nextToken() // common entry point │ ├─ ReaderBasedJsonParser → _parsePunctuationMark() ├─ UTF8StreamJsonParser → _parsePunctuationMark() ├─ UTF8DataInputJsonParser → _parsePunctuationMark() └─ NonBlockingJsonParserBase → _startArrayScope() / _startObjectScope() │ ▼ _parsingContext.createChildArrayContext() // '[' encountered _parsingContext.createChildObjectContext() // '{' encountered ⚠ no depth check — context chain grows without bound
جميع تطبيقات `JsonParser` الأربعة تشترك في هذا العيب. ويمكن استغلال الهجوم بالتساوي عبر أيٍّ منها — سواء وصل الإدخال عبر `InputStream` أو `Reader` أو `DataInput` أو واجهة برمجة التطبيقات غير المتزامنة للتغذية غير الحاجبة (non-blocking feeder API).
**نواقل الهجوم:**
| # | الاستراتيجية | حمولة مثال | زيادة العمق | المحللات المتأثرة |
|---|----------|----------------|-----------------|------------------|
| 1 | تداخل المصفوفات | `[[[…]]]` — 1,001 رمز `[` متتالية | +1 لكل `[` | جميع الأربعة |
| 2 | تداخل الكائنات | `{"k":{"k":{…}}}` — 1,001 رمز `{` متتالية | +1 لكل `{` | جميع الأربعة |
| 3 | التداخل المتناوب | `[{"k":[{"k":…}]}]` — 1,001 رمز مختلط `[`/`{` | +1 لكل `[` أو `{` | جميع الأربعة |
ملاحظات رئيسية:
- **تداخل المصفوفات — حمل إضافي ضئيل:** لا يتطلب سوى رمزي `[` و`]`؛ لا مفاتيح ولا قيم ولا مسافات بيضاء. حمولة من 2,002 بايت مكوّنة من 1,001 زوج أقواس كافية لتجاوز الحد الافتراضي البالغ 1,000.
- **تداخل الكائنات — ضغط مضاعف على الكومة (heap):** كل `{` يخصص بالإضافة إلى ذلك فتحة مفتاح لـ`JsonReadContext` فوق عقدة سلسلة العمق، مما يضاعف استهلاك الذاكرة في الأعماق القصوى.
- **التداخل المتناوب — مراوغة جدار حماية تطبيقات الويب (WAF):** الدفاعات القائمة على مطابقة الأنماط التي تكتشف تكرار تسلسلات `[[[` أو `{{{` لا تكتشف التداخل المتناوب للرموز؛ عداد عمق المحلل يزداد بشكل مماثل بغض النظر عن نوع الرمز.
- **المغذي غير الحاجب — نفس الحمولة، سطح توصيل مختلف:** جميع استراتيجيات التداخل الثلاث قابلة للاستغلال بالتساوي عبر `NonBlockingJsonParser` وواجهة برمجة التطبيقات `ByteArrayFeeder`. يمكن تسليم الوثيقة في أجزاء صغيرة بشكل تعسفي؛ تقوم `NonBlockingJsonParserBase._startArrayScope()` / `_startObjectScope()` بزيادة عداد العمق عند كل رمز يفتح سياقًا بغض النظر عن كيفية وصول البايتات، مما يراكم العمق عبر استدعاءات `feedInput()` المتعددة.
جميع استراتيجيات التداخل الثلاث قابلة للوصول من خلال أيٍّ من تطبيقات `JsonParser` الأربعة. مع الإصدار 2.13.5، ينجح التحليل بصمت؛ مع هذا الإصلاح، ترمي المتجهات الثلاثة `StreamConstraintsException: Depth (1001) exceeds the maximum allowed nesting depth (1000)`.
---
### Sonatype-2022-6438 — طول الرمز الرقمي غير المحدود
**تفاصيل الأمان**
| الحقل | القيمة |
|-------|-------|
| معرّف Sonatype | [sonatype-2022-6438](https://guide.sonatype.com/vulnerability/sonatype-2022-6438/security-details) |
| الوصف | jackson-core — رفض الخدمة (DoS) |
| تاريخ النشر | 2022-12-07 |
| المصدر | Sonatype |
| درجة CVSS v3.1 | **7.5 عالية** — `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` |
| CWE | [CWE-770](https://cwe.mitre.org/data/definitions/770.html) — تخصيص الموارد دون حدود أو تقييد |
| درجة EPSS | 0% |
| طلبات سحب الإصلاح من المنبع | [jackson-core#827](https://github.com/FasterXML/jackson-core/pull/827), [jackson-core#846](https://github.com/FasterXML/jackson-core/pull/846) |
**الطرق المعرضة للخطر (حسب تحديد Sonatype)**
| الطريقة | ملاحظات |
|--------|-------|
| `com.fasterxml.jackson.core.base.ParserBase._parseSlowInt(I)V` | معامل عرضة للخطر: الفهرس 0 |
| `com.fasterxml.jackson.core.base.ParserBase.convertNumberToBigDecimal()V` | |
| `com.fasterxml.jackson.core.base.ParserMinimalBase.getValueAsDouble(D)D` | معامل عرضة للخطر: الفهرس 0 |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsDecimal()` | يُرجع `BigDecimal` |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsDouble(Z)D` | |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsFloat(Z)F` | |
تعالج كل من هذه الطرق مخزن الأرقام الخام دون التحقق أولاً من طوله. تمرير رمز رقمي طويل بما يكفي يؤدي إلى تخصيص غير محدود في الكومة واستنزاف وحدة المعالجة المركزية (CPU) عندما يحاول JVM إنشاء مثيل لـ`BigInteger` أو `BigDecimal` من محتويات المخزن غير المقيدة.
---
**السبب الجذري:** قبل الإصدار 2.15.0، لم يفرض `JsonParser` أي حد على طول البايتات لرموز الأعداد الصحيحة، والتدوين العلمي، وأعداد الفاصلة العائمة البسيطة، وأعداد الفاصلة العائمة المركبة. عندما يخصص المحلل مخزنه الداخلي `_textBuffer` لتجميع الأرقام، يمكن للمهاجم توفير رقم بملايين الأرقام، مما يؤدي إلى نمو المخزن دون حدود وفي النهاية استنفاد ذاكرة الكومة.
**مسارات التعليمات البرمجية المعرضة للخطر:**
يوجد مساران معرضان للخطر ومتميزان بنيويًا — أحدهما مشترك بين المحللات المتزامنة الثلاثة، والثاني مسار مستقل عبر المحلل غير المتزامن.
**المسار أ — المحللات المتزامنة** (ثلاثة تطبيقات، مصبّ مشترك واحد):```
JsonParser.nextToken() // common entry point
│
├─ ReaderBasedJsonParser ─┐
├─ UTF8StreamJsonParser ├─→ ParserBase.resetInt() / resetFloat()
└─ UTF8DataInputJsonParser ─┘ │
▼
_textBuffer.contentsAsString()
⚠ no length check — buffer grows without bound
المسار B — المحلل غير المتزامن (مسار كود مستقل، غير محمي بشكل منفصل):``` NonBlockingJsonParser.nextToken() │ ├─ _startPositiveNumber() / _startNegativeNumber() // integer paths ├─ _finishNumberIntegralPart() ├─ _startFloat() // floating-point paths ├─ _finishFloatFraction() └─ _finishFloatExponent() │ ▼ writes _intLength / _fractLength / _expLength directly ⚠ never calls ParserBase.resetInt() / resetFloat() ⚠ constraint validation bypassed entirely
محلل عدم الحجب (غير المتزامن) هو سطح هجوم بارز بشكل خاص: فهو يحتوي على
حلقاته الخاصة لتراكم الأرقام في `_startPositiveNumber`، و`_startNegativeNumber`،
و`_finishNumberIntegralPart`، و`_startFloat`، و`_finishFloatFraction`، و`_finishFloatExponent`
التي تضبط `_intLength` / `_fractLength` / `_expLength` مباشرة دون المرور أبدًا عبر
`ParserBase.resetInt()` أو `resetFloat()`. هذا يعني أن إصلاح PR #827 من المنبع (الذي أضاف
التحقق إلى `ParserBase` فقط) **ترك `NonBlockingJsonParser` غير محمي تمامًا**.
تم اكتشاف ذلك أثناء تحليل موسع لسطح الهجوم وتمت معالجته في هذا الفرع.
**نواقل الهجوم:**
| # | شكل التوكن | مثال على الحمولة | `intLen` | `fractLen` | `expLen` | الإجمالي | القيد |
|---|------------|----------------|----------|------------|----------|-------|------------|
| 1 | عدد صحيح | `999…` — 199,999 رقمًا متتاليًا | 199,999 | 0 | 0 | 199,999 | `validateIntegerLength` |
| 2 | كسر عشري | `0.999…` — عدد صحيح من رقم واحد، وجزء كسري من 1,001 رقم | 1 | 1,001 | 0 | 1,002 | `validateFPLength` |
| 3 | تدوين علمي | `1e999…` — معامل من رقم واحد، وأس من 1,001 رقم | 1 | 0 | 1,001 | 1,002 | `validateFPLength` |
| 4 | نقطة عائمة مركبة | `0.999…e999…` — جزء كسري من 500 رقم، وأس من 500 رقم | 1 | 500 | 500 | 1,001 | `validateFPLength` |
ملاحظات رئيسية:
- **العدد الصحيح — حرف الإشارة البادئ ليس رقمًا:** يتم استبعاد `-` البادئة من تراكم الأرقام؛ ينتج كل من `-999…` و`999…` قيمتي `intLen` متطابقتين ويطلقان القيد عند نفس العتبة.
- **الكسر العشري — عدد صحيح قصير وكسر غير محدود:** قد يكون الجزء الصحيح رقمًا واحدًا (0) بينما ينمو الجزء الكسري بدون حد؛ وتُستبعد النقطة العشرية نفسها من العد.
- **التدوين العلمي — مضغوط لكنه كارثي:** عند ~1,004 بايت، هذه هي أصغر حمولة فعالة؛ فهي تُجبر على إنشاء كائن `BigDecimal` بمقياس ±10^1001، مما يتطلب تخصيصًا غير محدود لذاكرة الكومة الوسيطة رغم صغر حجم التوكن.
- **النقطة العائمة المركبة — تفادي حد التقسيم:** مع `fractLen = 500` و`expLen = 500`، لا يصل أي مكوّن بمفرده إلى عتبة 1,000 رقم. الفحص الموحد `validateFPLength(intLen + fractLen + expLen)` هو الدفاع الوحيد الذي يسد هذه الفجوة.
- **المحلل غير الحاجب — تجاوز مستقل:** جميع أشكال التوكن الأربعة أعلاه قابلة للاستغلال بشكل مستقل عبر `NonBlockingJsonParser` من خلال `ByteArrayFeeder`. على عكس المحللات المتزامنة، يقوم `NonBlockingJsonParser` بتراكم الأرقام في حلقات خاصة (`_startPositiveNumber`, `_finishNumberIntegralPart`, `_startFloat`, `_finishFloatFraction`, `_finishFloatExponent`) تكتب `_intLength` / `_fractLength` / `_expLength` مباشرة، متجاوزًا `ParserBase.resetInt()` و`resetFloat()` تمامًا. لذلك، فإن PR #827 من المنبع — الذي عدّل `ParserBase` فقط — ترك هذا المحلل غير محمي تمامًا، مما استلزم ستة تصحيحات مستقلة في مواقع الاستدعاء في هذا الإصلاح.
يتم رفض جميع أشكال التوكن الأربعة والتجاوز غير الحاجب في وقت الترميز — قبل إنشاء أي `BigDecimal` أو `BigInteger`
— بواسطة `validateIntegerLength` و`validateFPLength` في `ParserBase` (المحللات المتزامنة)
وفي ستة مواقع استدعاء مخصصة في `NonBlockingJsonParser` (المحلل غير المتزامن). مع 2.13.5، يتم قبول جميع أشكال التوكن الأربعة بصمت؛ مع هذا الإصلاح، يرمي كل محلل
`StreamConstraintsException: Number length (N) exceeds the maximum length (1000)`.
> **ملاحظة حول `UTF8DataInputJsonParser` مع الحمولات الكبيرة:** يحتوي محلل DataInput على
> حد داخلي مسبق للذاكرة المؤقتة يبلغ 65 536 بايت ([jackson-core#493](https://github.com/FasterXML/jackson-core/issues/493)).
> المستندات التي تتجاوز هذا الحجم (مثل حمولات PoC المكونة من 199,999 رقمًا ≈ 200 كيلوبايت) تؤدي إلى
> `ArrayIndexOutOfBoundsException` قبل أن يتمكن قيد الطول من العمل. لذلك يتم التحقق من حماية طول الأرقام
> لمحلل `UTF8DataInputJsonParser` بحمولات أقصر
> (≤ 1,001 رقماً) حيث لا يزال الخطأ قابلاً للتكرار.
---
### SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9 — تجاوز قيد طول المستند
**تفاصيل الأمان**
| الحقل | القيمة |
|-------|-------|
| معرف Snyk | [SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551](https://security.snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551) |
| استشارة GitHub | [GHSA-2m67-wjpj-xhg9](https://github.com/FasterXML/jackson-core/security/advisories/GHSA-2m67-wjpj-xhg9) |
| الوصف | تخصيص الموارد دون حدود أو إبطاء |
| تاريخ الإفصاح | 2026-04-04 |
| درجة CVSS v4.0 | **8.7 عالية** |
| CWE | [CWE-770](https://cwe.mitre.org/data/definitions/770.html) — تخصيص الموارد دون حدود أو إبطاء |
| الإصدارات المتأثرة | [2.8.0, 2.21.2) |
| الإصلاح من المنبع | jackson-core 2.18.7 أو 2.21.2 أو أعلى |
| التزامات الإصلاح | [74c9ee25](https://github.com/FasterXML/jackson-core/commit/74c9ee25) (3.x), [7ce3622f](https://github.com/FasterXML/jackson-core/commit/7ce3622f) (2.18.x) |
**السبب الجذري:** حتى عند ضبط `StreamReadConstraints.maxDocumentLength`، فإن الإصدارات السابقة لـ
2.18.7 / 2.21.2 لا تفرض حد طول المستند في أي مسار محلل. المحللات الحاجبة
(`UTF8StreamJsonParser`، `ReaderBasedJsonParser`) لا تتحقق أبدًا من إجمالي البايتات المقروءة مقابل
الحد المضبوط. المحلل غير المتزامن (`NonBlockingJsonParser`) يفتقر بالمثل إلى التحقق في
`feedInput()`. لا يمتلك `UTF8DataInputJsonParser` أي آلية لتتبع إجمالي البايتات المستهلكة.
في jackson-core 2.13.5، لم يكن `maxDocumentLength` موجودًا على الإطلاق، مما يعني عدم وجود أي وسيلة
لتقييد حجم المستند. يقدم هذا الإصلاح الحقل `maxDocumentLength` في
`StreamReadConstraints` ويفرضه عبر جميع مسارات المحلل.
**مسارات المحلل القابلة للاستغلال:**
| المحلل | المسار | نقطة التنفيذ |
|--------|------|-------------------|
| `UTF8StreamJsonParser` | `InputStream` → `_loadMore()` | يتحقق من `_currInputProcessed + count` بعد كل إعادة تعبئة للذاكرة المؤقتة وعند EOF |
| `ReaderBasedJsonParser` | `Reader` → `_loadMore()` | النمط نفسه المتبع في `UTF8StreamJsonParser` |
| `NonBlockingJsonParser` | `feedInput()` | يتحقق من `_currInputProcessed + _origBufferLen` بعد كل جزء إدخال |
| `UTF8DataInputJsonParser` | `DataInput` | فشل سريع: يرمي `StreamConstraintsException` إذا تم ضبط `maxDocumentLength` |
**سيناريو الهجوم:** يرسل مهاجم مستند JSON صالحًا لكنه ضخم (مثل بنية متداخلة بعمق
أو شديدة التكرار تمتد لعدة غيغابايت) إلى خدمة ضبطت
`maxDocumentLength` لمنع استنزاف الموارد. بدون تنفيذ القيد، يعالج المحلل
المستند بأكمله بغض النظر عن الحد المضبوط، مستهلكًا ذاكرة وCPU غير محدودة.
---
## الأثر الأمني
جميع الثغرات الأربع قابلة للاستغلال عن بُعد دون الحاجة إلى أي مصادقة:
- أي خدمة تعالج JSON يتحكم فيه المهاجم عبر `JsonParser` (مباشرة أو من خلال
Jackson Databind، الذي يغلّف `jackson-core`) معرضة للخطر.
- الهجوم سهل البناء للغاية — بضع مئات من البايتات من JSON كافية لإحداث
استهلاك غير محدود للموارد.
- لا يوجد أي أثر على السرية أو النزاهة؛ الإتاحة (DoS) هي فئة الأثر الوحيدة.
---
## تفاصيل الإصلاح
### الترقية الرسمية (موصى بها)
قم بالترقية إلى **jackson-core 2.15.4** أو أي إصدار ثابت لاحق. جميع إصدارات 2.15.x و2.16+
تتضمن واجهة برمجة التطبيقات `StreamReadConstraints` بقيم افتراضية آمنة.```xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.4</version>
</dependency>
إذا لم يكن الترقية إلى إصدار لاحق ممكنة فورًا، فإن هذا الفرع يطبق إصلاحًا شاملًا على قاعدة كود 2.13.5. يقدم StreamReadConstraints و StreamConstraintsException بواجهة برمجة تطبيقات متوافقة مع 2.15.x، ويربط القيود في جميع تطبيقات JsonParser الأربعة — بما في ذلك المحلل غير المحظور، الذي لم يشمله الإصلاح من المصدر الرئيسي — ويفرض الحدود الافتراضية التالية:
| القيد | الحد الافتراضي |
|---|---|
| أقصى عمق للتداخل | 1,000 |
| أقصى طول لرمز رقمي | 1,000 رقم |
| أقصى طول لرمز نصي | 1,000,000 حرف |
أقصى مقدار لمقياس BigDecimal | 100,000 |
StreamReadConstraints (356 سطرًا)كائن قيمة غير قابل للتغيير يحمل حدود قراءة التدفق لكل محلل، ويتم إنشاؤه عبر Builder:```java // Default constraints (used by all parsers unless overridden) StreamReadConstraints defaults = StreamReadConstraints.defaults();
// Custom constraints StreamReadConstraints custom = StreamReadConstraints.builder() .maxNestingDepth(500) .maxNumberLength(2000) .maxStringLength(5000000) .build();
طرق التحقق (تُستدعى بواسطة المحللات عند كل رمز جديد):```java
void validateNestingDepth(int depth) throws StreamConstraintsException;
void validateIntegerLength(int length) throws StreamConstraintsException;
void validateFPLength(int length) throws StreamConstraintsException;
void validateStringLength(int length) throws StreamConstraintsException;
void validateBigIntegerScale(int scale) throws StreamConstraintsException;
Exception message format:
"Depth (%d) exceeds the maximum allowed nesting depth (%d)""Number length (%d) exceeds the maximum length (%d)""String length (%d) exceeds the maximum length (%d)""BigDecimal scale (%d) magnitude exceeds maximum allowed (%d)"StreamConstraintsException (52 سطرًا)ترث من StreamReadException (وهي نفسها JsonProcessingException). تُطرح حصريًا بواسطة
أساليب التحقق في StreamReadConstraints.
base/ParserBase.javaتمت إضافة الحقل _streamReadConstraints (القيمة الافتراضية له هي StreamReadConstraints.defaults()).
أصبحت resetInt() و resetFloat() الآن تتحققان من طول الرمز الرقمي فور تراكم الرمز:```java
protected void resetInt(boolean negative, int intLen) throws IOException {
_streamReadConstraints.validateIntegerLength(intLen);
// … existing reset logic …
}
protected void resetFloat(boolean negative, int intLen, int decLen, int expLen) throws IOException { int totalLen = intLen + decLen + expLen; _streamReadConstraints.validateFPLength(totalLen); // … existing reset logic … }
طرق مساعدة جديدة `_createChildArrayContext()` و `_createChildObjectContext()` تغلّف إنشاء السياق مع فحص العمق:```java
protected JsonReadContext _createChildArrayContext(int line, int col) throws IOException {
_streamReadConstraints.validateNestingDepth(_parsingContext.getNestingDepth() + 1);
return _parsingContext.createChildArrayContext(line, col);
}
جميع المحللات الأربعة تستدعي الآن أدوات فحص العمق الجديدة بدلاً من الوصول مباشرة إلى _parsingContext.createChild*():
json/ReaderBasedJsonParser.javajson/UTF8StreamJsonParser.javajson/UTF8DataInputJsonParser.javajson/async/NonBlockingJsonParserBase.javaJsonStreamContext.javaتمت إضافة getNestingDepth() التي تتنقل عبر سلسلة العقد الأب لحساب العمق المطلق:```java
public int getNestingDepth() {
int depth = 0;
JsonStreamContext curr = this;
while ((curr = curr.getParent()) != null) {
depth++;
}
return depth;
}
#### `json/JsonReadContext.java`
تم تحديث توقيعي `createChildArrayContext()` و `createChildObjectContext()` لنشر `throws IOException`.
#### `json/async/NonBlockingJsonParser.java` (Sonatype-2022-6438 فقط)
هذا هو الإصلاح الإضافي الرئيسي المكتشف خارج نطاق PR #827 upstream. تمت معالجة ستة مواقع لإكمال الأرقام كانت تتجاوز `ParserBase.resetInt()` بشكل فردي:
| Method | التحقق المضاف |
|--------|------------------|
| `_startPositiveNumber()` — إرجاع المسار السريع | `validateIntegerLength(_intLength)` |
| `_startNegativeNumber()` — إرجاع المسار السريع | `validateIntegerLength(_intLength)` |
| `_finishNumberIntegralPart()` — الإرجاع النهائي | `validateIntegerLength(_intLength)` |
| `_finishToken()` حالة `MINOR_NUMBER_INTEGER_DIGITS` | `validateIntegerLength(_intLength)` |
| `_startFloat()` / `_finishFloatFraction()` / `_finishFloatExponent()` الإرجاعات النهائية | `validateFPLength(_intLength + _fractLength + _expLength)` |
| `_finishToken()` حالات `MINOR_NUMBER_FRACTION_DIGITS` / `MINOR_NUMBER_EXPONENT_DIGITS` | `validateFPLength(...)` |
جميع المواقع قابلة للوصول: تتعامل طرق المسار السريع مع الحالة التي يكون فيها الرقم الكامل متاحًا في استدعاء `feedInput()` واحد؛ بينما تتعامل حالات استئناف `MINOR_*` مع الحالة المجزأة حيث تصل أرقام الرقم عبر استدعاءات متعددة. يجب حماية كلا المسارين.
---
## تغطية الاختبارات
### CVE-2025-52999 — اختبارات عمق التداخل
| Test File | Test Method | Parser modes | يغطي |
|-----------|-------------|-------------|--------|
| `read/ArrayParsingTest.java` | `testCVE_2025_52999` | stream | اجتياز تكراري يحاكي استخدام التطبيق الفعلي؛ يؤكد `StreamConstraintsException` عند العمق 1001 (تمت المعالجة) و `StackOverflowError` عند العمق 20,000 (2.13.5) |
| `read/ArrayParsingTest.java` | `testCustomNestingDepthConstraint` | direct API | `StreamReadConstraints.builder().maxNestingDepth(5)` — مُحدِد الوصول، نجاح عند الحد، رمي استثناء عند تجاوز الحد |
| `read/ArrayParsingTest.java` | `testObjectNestingDepthLimit` | stream | كائنات عند الحد 1000 تمامًا (نجاح)، كائنات بمستوى 1001 ترمي استثناءً |
| `read/ArrayParsingTest.java` | `testDataInputParserDepthLimit` | `UTF8DataInputJsonParser` | `UTF8DataInputJsonParser` يفرض حد العمق 1001 |
| `read/ArrayParsingTest.java` | `testNonBlockingParserDepthLimit` | non-blocking | `NonBlockingJsonParser` يفرض حد العمق 1001 |
### Sonatype-2022-6438 — اختبارات طول الأرقام
| Test File | Test Method | Parser modes | يغطي |
|-----------|-------------|-------------|--------|
| `read/NumberOverflowTest.java` | `testSonatype_2022_6438` | `ALL_MODES` | عدد صحيح عند الحد (نجاح)، عدد صحيح فوق الحد (فشل)، رقم عشري عند الحد (نجاح)، رقم عشري فوق الحد (فشل)، أس التدوين العلمي عند الحد (نجاح)، أس فوق الحد (فشل) — جميع المحللات الأربعة |
| `read/NumberOverflowTest.java` | `testNonBlockingParserNumericLengthLimit` | non-blocking | `NonBlockingJsonParser` يفرض حد طول الرقم |
| `read/NumberOverflowTest.java` | `testNonBlockingParserExponentLengthLimit` | non-blocking | `NonBlockingJsonParser` يفرض حد طول أس التدوين العلمي عبر `validateFPLength` |
| `read/NumberOverflowTest.java` | `testCustomMaxNumberLengthConstraint` | direct API | `StreamReadConstraints.builder().maxNumberLength(5)` — مُحدِد الوصول، نجاح عند الحد، رمي استثناء عند تجاوز الحد لكل من `validateIntegerLength()` و `validateFPLength()`، صيغة رسالة الخطأ |
> **مفتاح أوضاع المحلل:**
> - `ALL_STREAMING_MODES` = `UTF8StreamJsonParser` (stream)، `UTF8StreamJsonParser` (محدود السرعة)، `ReaderBasedJsonParser`
> - `ALL_MODES` = الأوضاع الثلاثة أعلاه + `UTF8DataInputJsonParser`
> - `non-blocking` = `NonBlockingJsonParser` عبر `ByteArrayFeeder`
> - `stream` = `UTF8StreamJsonParser` (الافتراضي في `JsonFactory.createParser`)
### SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 — اختبارات طول المستند
| Test File | Test Method | Parser modes | يغطي |
|-----------|-------------|-------------|--------|
| `constraints/LargeDocReadTest.java` | `testInputStreamExceedsLimit` | `UTF8StreamJsonParser` | محلل InputStream يفرض `maxDocumentLength` — مستند 20K مرفوض بحد 10K |
| `constraints/LargeDocReadTest.java` | `testInputStreamUnderLimitSucceeds` | `UTF8StreamJsonParser` | محلل InputStream يقبل مستندًا ضمن الحد |
| `constraints/LargeDocReadTest.java` | `testReaderExceedsLimit` | `ReaderBasedJsonParser` | محلل Reader يفرض `maxDocumentLength` — مستند 20K مرفوض بحد 10K |
| `constraints/LargeDocReadTest.java` | `testReaderUnderLimitSucceeds` | `ReaderBasedJsonParser` | محلل Reader يقبل مستندًا ضمن الحد |
| `constraints/LargeDocReadTest.java` | `testAsyncExceedsLimit` | `NonBlockingJsonParser` | المحلل غير المتزامن يفرض `maxDocumentLength` — مستند 20K مرفوض في `feedInput()` |
| `constraints/LargeDocReadTest.java` | `testAsyncUnderLimitSucceeds` | `NonBlockingJsonParser` | المحلل غير المتزامن يقبل مستندًا ضمن الحد |
| `constraints/LargeDocReadTest.java` | `testDataInputWithDocLengthLimitFails` | `UTF8DataInputJsonParser` | محلل DataInput يفشل بسرعة عند تكوين `maxDocumentLength` |
| `constraints/LargeDocReadTest.java` | `testDataInputWithoutDocLengthLimitWorks` | `UTF8DataInputJsonParser` | محلل DataInput يعمل بشكل طبيعي بدون تكوين `maxDocumentLength` |
| `constraints/LargeDocReadTest.java` | `testDefaultFactoryNoLimit` | `UTF8StreamJsonParser` | المصنع الافتراضي (بدون حد) يقبل المستندات الكبيرة |
---
## نتائج مجموعة الاختبارات الكاملة```
Tests run: 957, Failures: 0, Errors: 0, Skipped: 0
جميع الاختبارات البالغ عددها 957 تنجح في البناء المُصحَّح. تفصيل الاختبارات الأمنية الجديدة المضافة:
أمر البناء:```bash ./mvnw test
---
## نتائج التحقق
### اختبار الانحدار ضد jackson-core 2.13.5
تم تصميم طرق اختبار CVE بحيث **تفشل** على قاعدة كود 2.13.5 و**تنجح** على البناء المُصحح.
**`NumberOverflowTest#testSonatype_2022_6438`** مقابل 2.13.5:```
FAIL — Sonatype-2022-6438 VULNERABILITY PRESENT: parser returned VALUE_NUMBER_INT
for a 1001-digit integer — number length limit is not enforced
ArrayParsingTest#testCVE_2025_52999 ضد 2.13.5:```
FAIL — CVE-2025-52999 VULNERABILITY PRESENT: StackOverflowError after 20000 nesting
levels — parser enforces no depth limit (2.13.5)
**كلا الاختبارين على البناء المُعالج: PASS.**
---
## إثبات المفهوم
### CVE-2025-52999 — حجب الخدمة بعمق التداخل```java
// Build a 1001-level nested array document (just over the limit)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1001; i++) sb.append('[');
for (int i = 0; i < 1001; i++) sb.append(']');
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(sb.toString());
try {
while (parser.nextToken() != null) { } // ← throws on 1001st '['
System.err.println("VULNERABLE: no exception thrown");
} catch (StreamConstraintsException e) {
System.out.println("REMEDIATED: " + e.getMessage());
// Depth (1001) exceeds the maximum allowed nesting depth (1000)
} finally {
parser.close();
}
تؤدي جميع أشكال الرموز الأربعة إلى تشغيل validateFPLength / validateIntegerLength قبل أي محاولة لتحويل BigDecimal / BigInteger.```java
JsonFactory factory = new JsonFactory();
// ── 1. Long integer ────────────────────────────────────────────────────────── String longInt = "9".repeat(1001); // 1001-digit integer // Negative form works identically: "-" + "9".repeat(1001)
// ── 2. Long fractional part (floating-point) ───────────────────────────────── // intLen=1, fractLen=1001, total=1002 String longFloat = "0." + "9".repeat(1001);
// ── 3. Long exponent / scientific notation ─────────────────────────────────── // intLen=1, fractLen=0, expLen=1001, total=1002 — only 1,004 bytes on the wire String longExp = "1e" + "9".repeat(1001);
// ── 4. Combined fractional + exponent ──────────────────────────────────────── // intLen=1, fractLen=500, expLen=500, total=1001 — neither part alone is over the limit String combined = "0." + "9".repeat(500) + "e" + "9".repeat(500);
for (String payload : new String[]{ longInt, longFloat, longExp, combined }) { JsonParser parser = factory.createParser("[" + payload + "]"); try { parser.nextToken(); // START_ARRAY parser.nextToken(); // ← throws on the number token System.err.println("VULNERABLE: " + payload.substring(0, 20) + "…"); } catch (StreamConstraintsException e) { System.out.println("REMEDIATED: " + e.getMessage()); // Number length (N) exceeds the maximum length (1000) } finally { parser.close(); } }
---
## دليل الترحيل
### الخيار 1: الترقية إلى jackson-core 2.15.4+ (موصى به)```xml
<!-- Maven -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.4</version>
</dependency>
<!-- Or with Jackson BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.15.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
مع الإصدار 2.15+، يمكنك أيضًا ضبط الحدود في وقت التشغيل إذا كان تطبيقك يحتاج بشكل مشروع إلى تداخل أعمق أو أرقام أطول:```java JsonFactory factory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(2000) .maxNumberLength(10000) .maxDocumentLength(50_000_000L) .build()) .build();
### الخيار 2: تطبيق هذا الإصلاح الأمني```bash
git clone https://github.com/sassoftware/jackson-core.git
cd jackson-core
git checkout 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9
./mvnw install -DskipTests
ثم قم بتحديث تبعية مشروعك لاستخدام القطعة المثبتة محليًا 2.13.5-SNAPSHOT، أو
انشرها في مستودع القطع الداخلي الخاص بك.
الإجمالي: تغيّر 16 ملفًا، 1,606 إضافات (كما أبلغ عنها git diff jackson-core-2.13.5 --stat).
StreamReadConstraints (javadoc لإصدار 2.15): https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.15.4/com/fasterxml/jackson/core/StreamReadConstraints.htmlأي تطبيق يقوم بـ:
jackson-databind)فهو عرضة لكلتا الهجمتين.
حتى بعد المعالجة، ضع في اعتبارك:
maxRequestSize في حاويات Servlet)
لرفض هيئات الطلبات الكبيرة للغاية قبل استدعاء المحلل.StreamReadConstraints مخصص إذا كان تطبيقك يتطلب بشكل مشروع مستندات أكبر أو أعمق —
اضبط الحدود إلى الحد الأدنى الضروري لحالة الاستخدام الخاصة بك.| البعد | المتطلب |
|---|---|
| بناء JDK | Java 8 (JDK 1.8) أو أحدث — يتطلب هذا الفرع Java 8+ للبناء والاختبار |
| حد أدنى لـ JRE وقت التشغيل | Java 8 أو أحدث |
| Maven | 3.6.3 أو أحدث (الغلاف المرفق ./mvnw يلبي هذا تلقائيًا) |
ملاحظة: إصدار jackson-core 2.13.5 الأصلي كان يستهدف Java 6 (
-source 1.6 -target 1.6). اعتبارًا من هذا الفرع الأمني، يتطلب كل من البناء ووقت التشغيل Java 8 أو أحدث. لا تتغير أي واجهة برمجة تطبيقات عامة لـ Jackson 2.13؛ فقط بيئات تشغيل JDK 6/7 تفقد التوافق بسبب متطلبات Maven وJDK.
./mvnw test
./mvnw install -DskipTests
---
## الترخيص
مرخّص بموجب [رخصة أباتشي، الإصدار 2.0](https://www.apache.org/licenses/LICENSE-2.0).```
Copyright 2024–2025 The Jackson Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
مؤلف أبحاث ومعالجة الثغرات الأمنية : Jinwoo Hwang (https://JinwooHwang.com)
| المعرف | النوع | الخطورة | CVSS | الإصلاح الرسمي |
|---|
| CVE-2025-52999 | حجب الخدمة — عمق تداخل غير محدود | عالية | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.15.0 |
| Sonatype-2022-6438 / SNYK-JAVA-COMFASTERXMLJACKSONCORE-7569538 | حجب الخدمة — طول رمز رقمي غير محدود | عالية | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.15.0 |
| SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 | استنزاف الموارد دون حدود أو تقييد | عالية | 8.7 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.18.6, 2.21.1 أو أحدث |
| SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9 | استنزاف الموارد دون حدود أو تقييد — تجاوز قيد طول المستند | عالية | 8.7 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.18.7, 2.21.2 أو أحدث |
| الإصدار | CVE-2025-52999 | Sonatype-2022-6438 / SNYK-JAVA-COMFASTERXMLJACKSONCORE-7569538 | SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 | SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 |
|---|
| 2.13.5 | متأثر | متأثر | متأثر | متأثر |
| 2.13.5-CVE-2025-52999-sonatype-2022-6438 | معالَج | معالَج | معالَج | متأثر |
| 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 | معالَج | معالَج | معالَج | معالَج |
| 2.14.x | متأثر | متأثر | متأثر | متأثر |
| 2.15.x | معالَج | معالَج | متأثر | متأثر |
| 2.16.x | معالَج | معالَج | متأثر | متأثر |
| 2.17.x | معالَج | معالَج | متأثر | متأثر |
| 2.18.6+ | معالَج | معالَج | معالَج | متأثر |
| 2.18.7+ | معالَج | معالَج | معالَج | معالَج |
| 2.21.1+ | معالَج | معالَج | معالَج | متأثر |
| 2.21.2+ | معالَج | معالَج | معالَج | معالَج |
| الحقل | القيمة |
|---|
| معرف CVE | CVE-2025-52999 |
| تاريخ النشر | 2025-06-25 |
| آخر تعديل | 2025-06-26 |
| المصدر (CNA) | GitHub, Inc. |
| نقاط CVSS v4.0 | 8.7 عالية — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N |
| CWE | CWE-121 — تجاوز سعة المخزن المؤقت المعتمد على المكدس (Stack-based Buffer Overflow) |
| استشارة GitHub | GHSA-h46c-h94j-95f3 |
| PR الإصلاح الرسمي | jackson-core#943 |
| ملف الاختبار | الطرق الجديدة / الموسعة |
|---|
read/ArrayParsingTest.java | testCVE_2025_52999, testCustomNestingDepthConstraint, testObjectNestingDepthLimit, testDataInputParserDepthLimit, testNonBlockingParserDepthLimit |
read/NumberOverflowTest.java | testSonatype_2022_6438 (موسّع ليشمل حالات الأس), testNonBlockingParserNumericLengthLimit, testCustomMaxNumberLengthConstraint, testNonBlockingParserExponentLengthLimit |
constraints/LargeDocReadTest.java | testInputStreamExceedsLimit, testInputStreamUnderLimitSucceeds, testReaderExceedsLimit, testReaderUnderLimitSucceeds, testAsyncExceedsLimit, testAsyncUnderLimitSucceeds, testDataInputWithDocLengthLimitFails, testDataInputWithoutDocLengthLimitWorks, testDefaultFactoryNoLimit |
| الملف | نوع التغيير | الأسطر المتغيرة | الوصف |
|---|
src/main/java/.../StreamReadConstraints.java | جديد | +356 | إعدادات القيود + 5 طرق تحقق |
src/main/java/.../exc/StreamConstraintsException.java | جديد | +52 | نوع استثناء لانتهاكات القيود |
src/main/java/.../base/ParserBase.java | معدَّل | +44 | خطافات العمق/الطول في إعادة التعيين ومساعدات السياق |
src/main/java/.../json/JsonReadContext.java | معدَّل | +6 | نشر throws IOException |
src/main/java/.../json/ReaderBasedJsonParser.java | معدَّل | +30 | استخدام مساعدات فحص العمق _createChild* |
src/main/java/.../json/UTF8StreamJsonParser.java | معدَّل | +26 | استخدام مساعدات فحص العمق _createChild* |
src/main/java/.../json/UTF8DataInputJsonParser.java | معدَّل | +26 | استخدام مساعدات فحص العمق _createChild* |
src/main/java/.../json/async/NonBlockingJsonParserBase.java | معدَّل | +4 | استخدام مساعدات فحص العمق _createChild* |
src/main/java/.../json/async/NonBlockingJsonParser.java | معدَّل | +9 | جديد — validateIntegerLength / validateFPLength في 6 مواقع إكمال للأرقام؛ validateDocumentLength في feedInput() |
src/main/java/.../JsonStreamContext.java | معدَّل | +20 | إضافة getNestingDepth() |
src/main/java/.../TSFBuilder.java | معدَّل | +15 | إضافة حقل _streamReadConstraints ومُعيّن streamReadConstraints() |
src/main/java/.../JsonFactory.java | معدَّل | +12 | ربط قيود المُنشئ في المُنشئات؛ إخفاق سريع لـ DataInput عند maxDocumentLength |
src/test/java/.../read/NumberOverflowTest.java | معدَّل | +241 | testSonatype_2022_6438 (بما في ذلك حالات الأس)، testNonBlockingParserNumericLengthLimit, testNonBlockingParserExponentLengthLimit, testCustomMaxNumberLengthConstraint |
src/test/java/.../read/NumberParsingTest.java | معدَّل | +39 | تحديث 3 مواقع استدعاء لـ verifyException |
src/test/java/.../read/ArrayParsingTest.java | معدَّل | +143 | testCVE_2025_52999, testCustomNestingDepthConstraint |
src/test/java/.../constraints/LargeDocReadTest.java | جديد | +200 | 9 اختبارات لفرض maxDocumentLength عبر جميع مسارات المحلل |
| المكوّن | الإصدار |
|---|
| العلامة الأساسية | jackson-core-2.13.5 |
| الفرع | 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 |
| أداة البناء | Maven (الغلاف: ./mvnw) |
| إطار الاختبار | نمط JUnit 3 / TestCase |
| عدد الاختبارات | 957 |