CVE-2022-25867 (published 2022-08-02T14:15Z)

The package io.socket:socket.io-client before 2.0.1 are vulnerable to NULL Pointer Dereference when parsing a packet with with invalid payload format.

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-476
cwe_name: NULL Pointer Dereference
description: The product dereferences a pointer that it expects to be valid but is NULL.
extended_description: 
            
            
            
         
         

Fix information:
repo_url: https://github.com/socketio/socket.io-client-java
commit_details: repo_url: https://github.com/socketio/socket.io-client-java
author: Damien Arrachequesne
author_date: 2021-04-26 23:30:53+02:00
msg: fix: ensure the payload format is valid

This commit should prevent some NPE issues encountered after the
parsing of the packet.

Related:

- https://github.com/socketio/socket.io-client-java/issues/642
- https://github.com/socketio/socket.io-client-java/issues/609
- https://github.com/socketio/socket.io-client-java/issues/505
repository: repo_url: https://github.com/socketio/socket.io-client-java
repo_name: socketio/socket.io-client-java
description: Full-featured Socket.IO Client Library for Java, which is compatible with Socket.IO v1.0 and later.
repo_language: Java
owner: socketio
file_changes: filename: Manager.java
change_type: ModificationType.MODIFY
diff: @@ -326,10 +326,14 @@ public class Manager extends Emitter {
             @Override
             public void call(Object... objects) {
                 Object data = objects[0];
-                if (data instanceof String) {
-                    Manager.this.ondata((String)data);
-                } else if (data instanceof byte[]) {
-                    Manager.this.ondata((byte[])data);
+                try {
+                    if (data instanceof String) {
+                        Manager.this.decoder.add((String) data);
+                    } else if (data instanceof byte[]) {
+                        Manager.this.decoder.add((byte[]) data);
+                    }
+                } catch (DecodingException e) {
+                    logger.fine("error while decoding the packet: " + e.getMessage());
                 }
             }
         }));
@@ -353,22 +357,6 @@ public class Manager extends Emitter {
         });
     }
 
-    private void ondata(String data) {
-        try {
-            this.decoder.add(data);
-        } catch (DecodingException e) {
-            this.onerror(e);
-        }
-    }
-
-    private void ondata(byte[] data) {
-        try {
-            this.decoder.add(data);
-        } catch (DecodingException e) {
-            this.onerror(e);
-        }
-    }
-
     private void ondecoded(Packet packet) {
         this.emit(EVENT_PACKET, packet);
     }

programming_language: Java
filename: IOParser.java
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,9 @@
 package io.socket.parser;
 
 import io.socket.hasbinary.HasBinary;
+import org.json.JSONArray;
 import org.json.JSONException;
+import org.json.JSONObject;
 import org.json.JSONTokener;
 
 import java.util.ArrayList;
@@ -183,6 +185,9 @@ final public class IOParser implements Parser {
                     logger.log(Level.WARNING, "An error occured while retrieving data from JSONTokener", e);
                     throw new DecodingException("invalid payload");
                 }
+                if (!isPayloadValid(p.type, p.data)) {
+                    throw new DecodingException("invalid payload");
+                }
             }
 
             if (logger.isLoggable(Level.FINE)) {
@@ -191,6 +196,26 @@ final public class IOParser implements Parser {
             return p;
         }
 
+        private static boolean isPayloadValid(int type, Object payload) {
+            switch (type) {
+                case Parser.CONNECT:
+                case Parser.CONNECT_ERROR:
+                    return payload instanceof JSONObject;
+                case Parser.DISCONNECT:
+                    return payload == null;
+                case Parser.EVENT:
+                case Parser.BINARY_EVENT:
+                    return payload instanceof JSONArray
+                            && ((JSONArray) payload).length() > 0
+                            && !((JSONArray) payload).isNull(0);
+                case Parser.ACK:
+                case Parser.BINARY_ACK:
+                    return payload instanceof JSONArray;
+                default:
+                    return false;
+            }
+        }
+
         @Override
         public void destroy() {
             if (this.reconstructor != null) {

programming_language: Java
filename: ByteArrayTest.java
change_type: ModificationType.MODIFY
diff: @@ -1,15 +1,15 @@
 package io.socket.parser;
 
-import io.socket.emitter.Emitter;
 import org.json.JSONArray;
 import org.json.JSONException;
-import org.json.JSONObject;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
+import static java.util.Arrays.asList;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 
@@ -19,9 +19,9 @@ public class ByteArrayTest {
     private static Parser.Encoder encoder = new IOParser.Encoder();
 
     @Test
-    public void encodeByteArray() {
-        Packet<byte[]> packet = new Packet<>(Parser.BINARY_EVENT);
-        packet.data = "abc".getBytes(Charset.forName("UTF-8"));
+    public void encodeByteArray() throws JSONException {
+        Packet<JSONArray> packet = new Packet<>(Parser.BINARY_EVENT);
+        packet.data = new JSONArray(asList("abc", "abc".getBytes(StandardCharsets.UTF_8)));
         packet.id = 23;
         packet.nsp = "/cool";
         Helpers.testBin(packet);
@@ -29,8 +29,8 @@ public class ByteArrayTest {
 
     @Test
     public void encodeByteArray2() {
-        Packet<byte[]> packet = new Packet<>(Parser.BINARY_EVENT);
-        packet.data = new byte[2];
+        Packet<JSONArray> packet = new Packet<>(Parser.BINARY_EVENT);
+        packet.data = new JSONArray(asList("2", new byte[] { 0, 1 }));
         packet.id = 0;
         packet.nsp = "/";
         Helpers.testBin(packet);
@@ -38,11 +38,11 @@ public class ByteArrayTest {
 
     @Test
     public void encodeByteArrayDeepInJson() throws JSONException {
-        JSONObject data = new JSONObject("{a: \"hi\", b: {}, c: {a: \"bye\", b: {}}}");
-        data.getJSONObject("b").put("why", new byte[3]);
-        data.getJSONObject("c").getJSONObject("b").put("a", new byte[6]);
+        JSONArray data = new JSONArray("[{a: \"hi\", b: {}, c: {a: \"bye\", b: {}}}]");
+        data.getJSONObject(0).getJSONObject("b").put("why", new byte[3]);
+        data.getJSONObject(0).getJSONObject("c").getJSONObject("b").put("a", new byte[6]);
 
-        Packet<JSONObject> packet = new Packet<>(Parser.BINARY_EVENT);
+        Packet<JSONArray> packet = new Packet<>(Parser.BINARY_EVENT);
         packet.data = data;
         packet.id = 999;
         packet.nsp = "/deep";
@@ -51,10 +51,10 @@ public class ByteArrayTest {
 
     @Test
     public void encodeDeepBinaryJSONWithNullValue() throws JSONException {
-        JSONObject data = new JSONObject("{a: \"b\", c: 4, e: {g: null}, h: null}");
-        data.put("h", new byte[9]);
+        JSONArray data = new JSONArray("[{a: \"b\", c: 4, e: {g: null}, h: null}]");
+        data.getJSONObject(0).put("h", new byte[9]);
 
-        Packet<JSONObject> packet = new Packet<>(Parser.BINARY_EVENT);
+        Packet<JSONArray> packet = new Packet<>(Parser.BINARY_EVENT);
         packet.data = data;
         packet.nsp = "/";
         packet.id = 600;

programming_language: Java
filename: ParserTest.java
change_type: ModificationType.MODIFY
diff: @@ -63,5 +63,8 @@ public class ParserTest {
         Helpers.testDecodeError(Parser.EVENT + "2sd");
         // event with invalid json data
         Helpers.testDecodeError(Parser.EVENT + "2[\"a\",1,{asdf}]");
+        Helpers.testDecodeError(Parser.EVENT + "2{}");
+        Helpers.testDecodeError(Parser.EVENT + "2[]");
+        Helpers.testDecodeError(Parser.EVENT + "2[null]");
     }
 }

programming_language: Java