CVE-2021-33806 (Scala, published 2021-06-03T12:15Z)
Description: value: The BDew BdLib library before 1.16.1.7 for Minecraft allows remote code execution because it deserializes untrusted data in ObjectInputStream.readObject as part of its use of Java serialization.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-502 \u2014 Deserialization of Untrusted Data
The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
Repository: https://github.com/bdew-minecraft/bdlib
Files changed:
build.properties
src/main/scala/net/bdew/lib/multiblock/data/OutputConfig.scala
src/main/scala/net/bdew/lib/multiblock/data/OutputConfigFluid.scala
src/main/scala/net/bdew/lib/multiblock/data/OutputConfigFluidSlots.scala
src/main/scala/net/bdew/lib/multiblock/data/OutputConfigItems.scala
src/main/scala/net/bdew/lib/multiblock/data/OutputConfigPower.scala
src/main/scala/net/bdew/lib/multiblock/gui/WidgetRSConfig.scala
src/main/scala/net/bdew/lib/multiblock/network/MsgOutputCfg.scala
src/main/scala/net/bdew/lib/multiblock/network/MsgOutputCfgRSMode.scala
src/main/scala/net/bdew/lib/multiblock/network/MsgOutputCfgSlot.scala
src/main/scala/net/bdew/lib/multiblock/network/MultiblockNetHandler.scala
src/main/scala/net/bdew/lib/network/BaseMessage.scala
src/main/scala/net/bdew/lib/network/NetChannel.scala
Commit message: reworked custom network code to not use java serialization


Vulnerable code:
mod.version=1.15.1
import net.bdew.lib.multiblock.network.MsgOutputCfgPayload
  def handleConfigPacket(m: MsgOutputCfgPayload): Unit
  def handleConfigPacket(m: MsgOutputCfgPayload): Unit = throw new NotImplementedException
import net.bdew.lib.multiblock.network.{MsgOutputCfgPayload, MsgOutputCfgRSMode}
  def handleConfigPacket(m: MsgOutputCfgPayload): Unit = m match {
    case MsgOutputCfgRSMode(r) => rsMode = r
import net.bdew.lib.multiblock.network.{MsgOutputCfgPayload, MsgOutputCfgSlot}
  override def handleConfigPacket(m: MsgOutputCfgPayload): Unit = m match {
    case MsgOutputCfgSlot(id) => slot = slotsDef.get(id)
import net.bdew.lib.multiblock.network.{MsgOutputCfgPayload, MsgOutputCfgRSMode}
  def handleConfigPacket(m: MsgOutputCfgPayload): Unit = m match {
    case MsgOutputCfgRSMode(r) => rsMode = r
import net.bdew.lib.multiblock.network.{MsgOutputCfgPayload, MsgOutputCfgRSMode}
  def handleConfigPacket(m: MsgOutputCfgPayload): Unit = m match {
    case MsgOutputCfgRSMode(r) => rsMode = r
import net.bdew.lib.multiblock.network.{MsgOutputCfg, MsgOutputCfgRSMode, MultiblockNetHandler}
    MultiblockNetHandler.sendToServer(MsgOutputCfg(output, MsgOutputCfgRSMode(next(cfg.rsMode))))
trait MsgOutputCfgPayload extends Serializable

case class MsgOutputCfg(output: Int, payload: MsgOutputCfgPayload) extends MultiblockNetHandler.Message
case class MsgOutputCfgRSMode(rsMode: RSMode.Value) extends MsgOutputCfgPayload
case class MsgOutputCfgSlot(slot: String) extends MsgOutputCfgPayload
object MultiblockNetHandler extends NetChannel("multiblock", "1") {
  regServerContainerHandler(1, classOf[MsgOutputCfg], classOf[ContainerOutputFaces]) { (msg, cont, _) =>
    cont.te.outputConfig(msg.output).handleConfigPacket(msg.payload)
abstract class BaseMessage[CH <: NetChannel] extends Serializable
package net.bdew.lib.network

import net.minecraft.nbt.CompoundNBT

import java.io.{ObjectInputStream, ObjectOutputStream}

class CompoundNBTSerialize(var tag: CompoundNBT = new CompoundNBT) extends Serializable {
  private def writeObject(out: ObjectOutputStream): Unit = {
    out.writeObject(NBTHelper.toBytes(tag))
  }

  private def readObject(in: ObjectInputStream): Unit = {
    tag = NBTHelper.fromBytes(in.readObject().asInstanceOf[Array[Byte]])
  }
}

object CompoundNBTSerialize {

  import scala.language.implicitConversions

  implicit def ser2content(v: CompoundNBTSerialize): CompoundNBT = v.tag
  implicit def content2ser(v: CompoundNBT): CompoundNBTSerialize = new CompoundNBTSerialize(v)
}
import io.netty.buffer.{ByteBufInputStream, ByteBufOutputStream}
import java.io.{ObjectInputStream, ObjectOutputStream}
  private def encodeMsg[M <: Message](m: Message, p: PacketBuffer): Unit = {
    val writer = new ObjectOutputStream(new ByteBufOutputStream(p))
    writer.writeObject(m)
  }

  private def decodeMsg[M <: Message](p: PacketBuffer): M = {
    val reader = new ObjectInputStream(new ByteBufInputStream(p))
    reader.readObject().asInstanceOf[M]
  def regServerHandler[M <: Message](id: Int, cls: Class[M])(handler: (M, NetworkEvent.Context) => Unit): Unit = {
    channel.registerMessage[M](id, cls, (m, p) => encodeMsg[M](m, p), m => decodeMsg(m),
  def regServerContainerHandler[M <: Message, C <: Container](id: Int, cls: Class[M], cont: Class[C])(handler: (M, C, NetworkEvent.Context) => Unit): Unit = {
    regServerHandler(id, cls) { (msg, ctx) =>
  def regClientHandler[M <: Message](id: Int, cls: Class[M])(handler: M => Unit): Unit = {
    channel.registerMessage[M](id, cls, (m, p) => encodeMsg[M](m, p), m => decodeMsg(m),

Fixed code:
mod.version=1.16.0
import net.bdew.lib.multiblock.network.MsgOutputCfg
  def handleConfigPacket(m: MsgOutputCfg): Unit
  def handleConfigPacket(m: MsgOutputCfg): Unit = throw new NotImplementedException
import net.bdew.lib.multiblock.network.{MsgOutputCfg, MsgOutputCfgRSMode}
  def handleConfigPacket(m: MsgOutputCfg): Unit = m match {
    case MsgOutputCfgRSMode(_, r) => rsMode = r
import net.bdew.lib.multiblock.network.{MsgOutputCfg, MsgOutputCfgSlot}
  override def handleConfigPacket(m: MsgOutputCfg): Unit = m match {
    case MsgOutputCfgSlot(_, id) => slot = slotsDef.get(id)
import net.bdew.lib.multiblock.network.{MsgOutputCfg, MsgOutputCfgRSMode}
  def handleConfigPacket(m: MsgOutputCfg): Unit = m match {
    case MsgOutputCfgRSMode(_, r) => rsMode = r
import net.bdew.lib.multiblock.network.{MsgOutputCfg, MsgOutputCfgRSMode}
  def handleConfigPacket(m: MsgOutputCfg): Unit = m match {
    case MsgOutputCfgRSMode(_, r) => rsMode = r
import net.bdew.lib.multiblock.network.{MsgOutputCfgRSMode, MultiblockNetHandler}
    MultiblockNetHandler.sendToServer(MsgOutputCfgRSMode(output, next(cfg.rsMode)))
trait MsgOutputCfg {
  def output: Int
}
import net.minecraft.network.PacketBuffer
case class MsgOutputCfgRSMode(output: Int, rsMode: RSMode.Value) extends MultiblockNetHandler.Message with MsgOutputCfg

object CodecOutputCfgRSMode extends MultiblockNetHandler.Codec[MsgOutputCfgRSMode] {
  override def encodeMsg(m: MsgOutputCfgRSMode, p: PacketBuffer): Unit = {
    p.writeVarInt(m.output)
    p.writeByte(m.rsMode.id)
  }

  override def decodeMsg(p: PacketBuffer): MsgOutputCfgRSMode =
    MsgOutputCfgRSMode(p.readVarInt(), RSMode(p.readByte()))
}
import net.minecraft.network.PacketBuffer

case class MsgOutputCfgSlot(output: Int, slot: String) extends MultiblockNetHandler.Message with MsgOutputCfg

object CodecOutputCfgSlot extends MultiblockNetHandler.Codec[MsgOutputCfgSlot] {
  override def encodeMsg(m: MsgOutputCfgSlot, p: PacketBuffer): Unit = {
    p.writeVarInt(m.output)
    p.writeUtf(m.slot)
  }

  override def decodeMsg(p: PacketBuffer): MsgOutputCfgSlot = {
    MsgOutputCfgSlot(p.readVarInt(), p.readUtf(100))
  }
}
object MultiblockNetHandler extends NetChannel("multiblock", "2") {
  private def forwardConfigMsg(m: MsgOutputCfg, cont: ContainerOutputFaces): Unit = {
    cont.te.outputConfig(m.output).handleConfigPacket(m)

  regServerContainerHandler(1, CodecOutputCfgRSMode, classOf[ContainerOutputFaces]) { (msg, cont, _) =>
    forwardConfigMsg(msg, cont)
  }

  regServerContainerHandler(2, CodecOutputCfgSlot, classOf[ContainerOutputFaces]) { (msg, cont, _) =>
    forwardConfigMsg(msg, cont)
  }
abstract class BaseMessage[CH <: NetChannel]
import scala.reflect.ClassTag
  abstract class Codec[M <: Message : ClassTag] {
    val cls: Class[M] = implicitly[ClassTag[M]].runtimeClass.asInstanceOf[Class[M]]
    def encodeMsg(m: M, p: PacketBuffer): Unit
    def decodeMsg(p: PacketBuffer): M
  def regServerHandler[M <: Message](id: Int, codec: Codec[M])(handler: (M, NetworkEvent.Context) => Unit): Unit = {
    channel.registerMessage[M](id, codec.cls, codec.encodeMsg, codec.decodeMsg,
  def regServerContainerHandler[M <: Message, C <: Container](id: Int, codec: Codec[M], cont: Class[C])(handler: (M, C, NetworkEvent.Context) => Unit): Unit = {
    regServerHandler(id, codec) { (msg, ctx) =>
  def regClientHandler[M <: Message](id: Int, codec: Codec[M])(handler: M => Unit): Unit = {
    channel.registerMessage[M](id, codec.cls, codec.encodeMsg, codec.decodeMsg,