CVE-2022-48623: Insufficient Information (NVD-CWE-noinfo)
value: The Cpanel::JSON::XS package before 4.33 for Perl performs out-of-bounds accesses in a way that allows attackers to obtain sensitive information or cause a denial of service.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-02-13T05:15Z
Repository: https://github.com/rurban/Cpanel-JSON-XS
Language: Other
Files changed: XS.xs
Commit date: 2023-02-21 11:00:16 +0100
Commit message: fix decode out-of-bounds

on hash keys without :
security: could leak secrets.
Fixes GH 208

Diff: diff --git a/XS.xs b/XS.xs
index 419e07e..bbe1a8b 100644
--- a/XS.xs
+++ b/XS.xs
@@ -2722,10 +2722,12 @@ decode_comment (dec_t *dec)
 }
 
 INLINE void
 decode_ws (dec_t *dec)
 {
+  if (dec->cur >= dec->end)
+    return;
   for (;;)
     {
       char ch = *dec->cur;
 
       if (ch > 0x20)
@@ -2748,11 +2750,11 @@ decode_ws (dec_t *dec)
     }
 }
 
 #define ERR(reason) SB dec->err = reason; goto fail; SE
 
-#define EXPECT_CH(ch) SB \
+#define EXPECT_CH(ch) SB        \
   if (*dec->cur != ch)		\
     ERR (# ch " expected");	\
   ++dec->cur;			\
   SE
 
@@ -3921,11 +3923,12 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                         // not an AvREF
                         ERR ("Invalid dupkeys_as_arrayref hash key");
                       }
                     } // else overwrite it below
                   }
-                  decode_ws (dec); EXPECT_CH (':');
+                  decode_ws (dec);
+                  EXPECT_CH (':');
                   decode_ws (dec);
 
                   if (typesv)
                     {
                       value_typesv = newSV (0);
@@ -3993,11 +3996,14 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                       }
                     } // else overwrite it below
                   }
 
                   dec->cur = p + 1;
-                  decode_ws (dec); if (*p != ':') EXPECT_CH (':');
+                  if (dec->cur >= dec->end)
+                    EXPECT_CH (':');
+                  decode_ws (dec);
+                  if (*p != ':') EXPECT_CH (':');
                   decode_ws (dec);
 
                   if (typesv)
                     {
                       value_typesv = newSV (0);
@@ -4024,10 +4030,14 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
                       hv_store_str (aTHX_ hv, key, len, value);
                     }
                   break;
                 }
               ++p;
+              if (p > dec->end) {
+                dec->cur = p;
+                EXPECT_CH (':');
+              }
             }
         }
 
         decode_ws (dec);
 
@@ -4483,26 +4493,31 @@ decode_json (pTHX_ SV *string, JSON *json, STRLEN *offset_return, SV *typesv)
   }
 
   if (!sv)
     {
       SV *uni = sv_newmortal ();
-
+      COP cop = *PL_curcop;
+      if (dec.cur >= dec.end) // overshoot
+        {
+          croak ("%s, at character offset %d",
+                 dec.err,
+                 (int)ptr_to_index (aTHX_ string, dec.cur - SvPVX(string)));
+        }
 #if PERL_VERSION >= 8
       /* horrible hack to silence warning inside pv_uni_display */
       /* TODO: Can be omitted with newer perls */
-      COP cop = *PL_curcop;
       cop.cop_warnings = pWARN_NONE;
       ENTER;
       SAVEVPTR (PL_curcop);
       PL_curcop = &cop;
       pv_uni_display (uni, (U8*)dec.cur, dec.end - dec.cur, 20, UNI_DISPLAY_QQ);
       LEAVE;
 #endif
       croak ("%s, at character offset %d (before \"%s\")",
              dec.err,
              (int)ptr_to_index (aTHX_ string, dec.cur - SvPVX(string)),
-             dec.cur != dec.end ? SvPV_nolen (uni) : "(end of string)");
+             dec.cur < dec.end ? SvPV_nolen (uni) : "(end of string)");
     }
 
   if (!(dec.json.flags & F_ALLOW_NONREF) && json_nonref(aTHX_ sv)) {
     SvREFCNT_dec (sv);
     croak ("JSON text must be an object or array (but found number, string, true, false or null, use allow_nonref to allow this)");

Vulnerable code: #define EXPECT_CH(ch) SB \
                  decode_ws (dec); EXPECT_CH (':');
                  decode_ws (dec); if (*p != ':') EXPECT_CH (':');

      COP cop = *PL_curcop;
             dec.cur != dec.end ? SvPV_nolen (uni) : "(end of string)");
Fixed code:   if (dec->cur >= dec->end)
    return;
#define EXPECT_CH(ch) SB        \
                  decode_ws (dec);
                  EXPECT_CH (':');
                  if (dec->cur >= dec->end)
                    EXPECT_CH (':');
                  decode_ws (dec);
                  if (*p != ':') EXPECT_CH (':');
              if (p > dec->end) {
                dec->cur = p;
                EXPECT_CH (':');
              }
      COP cop = *PL_curcop;
      if (dec.cur >= dec.end) // overshoot
        {
          croak ("%s, at character offset %d",
                 dec.err,
                 (int)ptr_to_index (aTHX_ string, dec.cur - SvPVX(string)));
        }
             dec.cur < dec.end ? SvPV_nolen (uni) : "(end of string)");