VYPR
Medium severity5.3OSV Advisory· Published Sep 5, 2025· Updated Apr 15, 2026

CVE-2025-58369

CVE-2025-58369

Description

fs2 is a compositional, streaming I/O library for Scala. Versions up to and including 2.5.12, 3.0.0-M1 through 3.12.2, and 3.13.0-M1 through 3.13.0-M6 are vulnerable to denial of service attacks though TLS sessions using fs2-io on the JVM using the fs2.io.net.tls package. When establishing a TLS session, if one side of the connection shuts down write while the peer side is awaiting more data to progress the TLS handshake, the peer side will spin loop on the socket read, fully utilizing a CPU. The CPU is consumed until the overall connection is closed, potentially shutting down a fs2-io powered server. This issue is fixed in versions 2.5.13, 3.12.1, and 3.13.0-M7.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
co.fs2:fs2-io_2.12Maven
>= 3.0.0-M1, < 3.12.23.12.2
co.fs2:fs2-io_2.12Maven
>= 3.13.0-M1, < 3.13.0-M73.13.0-M7
co.fs2:fs2-io_2.13Maven
>= 3.0.0-M1, < 3.12.23.12.2
co.fs2:fs2-io_2.13Maven
>= 3.13.0-M1, < 3.13.0-M73.13.0-M7
co.fs2:fs2-io_3Maven
>= 3.0.0-M1, < 3.12.23.12.2
co.fs2:fs2-io_3Maven
>= 3.13.0-M1, < 3.13.0-M73.13.0-M7
co.fs2:fs2-io_0.26Maven
>= 0
co.fs2:fs2-io_0.27Maven
>= 0
co.fs2:fs2-io_2.11Maven
>= 0
co.fs2:fs2-io_2.12.0-M4Maven
>= 0
co.fs2:fs2-io_2.12.0-RC1Maven
>= 0
co.fs2:fs2-io_2.12.0-M5Maven
>= 0
co.fs2:fs2-io_2.12.0-RC2Maven
>= 0
co.fs2:fs2-io_2.13.0-M5Maven
>= 0
co.fs2:fs2-io_2.12Maven
< 2.5.132.5.13
co.fs2:fs2-io_2.13Maven
< 2.5.132.5.13
co.fs2:fs2-io_3Maven
< 2.5.132.5.13

Affected products

1
  • Range: redesign-complex-interpreter, release/0.5, release/0.7, …

Patches

4
edf0c4f2e660

Merge pull request #3624 from augi/patch-1

https://github.com/typelevel/fs2Michael PilquistOct 2, 2025via ghsa
1 file changed · +1 4
  • io/src/main/scala/fs2/io/tls/TLSEngine.scala+1 4 modified
    @@ -218,10 +218,7 @@ private[tls] object TLSEngine {
                   else
                     binding.read(engine.getSession.getPacketBufferSize, timeout).flatMap {
                       case Some(c) => unwrapBuffer.input(c) >> unwrapHandshake(timeout)
    -                  case None =>
    -                    unwrapBuffer.inputRemains.flatMap(x =>
    -                      if (x > 0) Applicative[F].unit else stopUnwrap
    -                    )
    +                  case None => stopUnwrap
                     }
                 }
               case SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN =>
    
46e2dc3abf99

Merge pull request #3603 from mtomko/backport

https://github.com/typelevel/fs2Michael PilquistSep 4, 2025via ghsa
2 files changed · +19 1
  • io/jvm/src/main/scala/fs2/io/net/SelectingSocketGroup.scala+7 1 modified
    @@ -22,6 +22,8 @@
     package fs2
     package io.net
     
    +import scala.concurrent.duration._
    +
     import cats.effect.LiftIO
     import cats.effect.Selector
     import cats.effect.kernel.Async
    @@ -100,7 +102,11 @@ private final class SelectingSocketGroup[F[_]: LiftIO: Dns](selector: Selector)(
       ): Resource[F, (SocketAddress[IpAddress], Stream[F, Socket[F]])] =
         Resource
           .make(F.delay(selector.provider.openServerSocketChannel())) { ch =>
    -        F.delay(ch.close())
    +        def waitForDeregistration: F[Unit] =
    +          // sleep time set to be short enough to not noticeably delay shutdown but long enough to
    +          // give the runtime/cpu time to do something else; some guesswork involved here
    +          F.delay(ch.isRegistered()).ifM(F.sleep(2.millis) >> waitForDeregistration, F.unit)
    +        F.delay(ch.close()) >> waitForDeregistration
           }
           .evalMap { serverCh =>
             val configure = address.traverse(_.resolve).flatMap { ip =>
    
  • io/shared/src/test/scala/fs2/io/net/tcp/SocketSuite.scala+12 0 modified
    @@ -269,6 +269,18 @@ class SocketSuite extends Fs2Suite with SocketSuitePlatform {
           }
         }
     
    +    test("sockets are released at the end of the resource scope") {
    +      val f =
    +        Network[IO].serverResource(port = Some(port"9071")).use { case (bindAddress, clients) =>
    +          clients.foreach(_ => IO.sleep(1.second)).compile.drain.background.surround {
    +            Network[IO].client(bindAddress).use { client =>
    +              client.read(1).assertEquals(None)
    +            }
    +          }
    +        }
    +      f >> f >> f
    +    }
    +
         test("endOfOutput / endOfInput ignores ENOTCONN") {
           Network[IO].serverResource().use { case (bindAddress, clients) =>
             Network[IO].client(bindAddress).surround(IO.sleep(100.millis)).background.surround {
    
55b55dbe3199

Fix compilation due to merge issue

https://github.com/typelevel/fs2Michael PilquistSep 4, 2025via osv
1 file changed · +1 0
  • io/jvm/src/test/scala/fs2/io/net/tls/TLSSocketSuite.scala+1 0 modified
    @@ -237,6 +237,7 @@ class TLSSocketSuite extends TLSSuite {
             @deprecated("", "")
             def remoteAddress = raw.remoteAddress
             def writes = raw.writes
    +        def metrics = raw.metrics
     
             def address = raw.address
             def getOption[A](key: SocketOption.Key[A]) = raw.getOption(key)
    
5c6c4c6c1ef3

Merge pull request #3591 from mtomko/main

https://github.com/typelevel/fs2Michael PilquistAug 26, 2025via ghsa
2 files changed · +19 1
  • io/jvm/src/main/scala/fs2/io/net/SelectingSocketGroup.scala+7 1 modified
    @@ -22,6 +22,8 @@
     package fs2
     package io.net
     
    +import scala.concurrent.duration._
    +
     import cats.effect.LiftIO
     import cats.effect.Selector
     import cats.effect.kernel.Async
    @@ -100,7 +102,11 @@ private final class SelectingSocketGroup[F[_]: LiftIO: Dns](selector: Selector)(
       ): Resource[F, (SocketAddress[IpAddress], Stream[F, Socket[F]])] =
         Resource
           .make(F.delay(selector.provider.openServerSocketChannel())) { ch =>
    -        F.delay(ch.close())
    +        def waitForDeregistration: F[Unit] =
    +          // sleep time set to be short enough to not noticeably delay shutdown but long enough to
    +          // give the runtime/cpu time to do something else; some guesswork involved here
    +          F.delay(ch.isRegistered()).ifM(F.sleep(2.millis) >> waitForDeregistration, F.unit)
    +        F.delay(ch.close()) >> waitForDeregistration
           }
           .evalMap { serverCh =>
             val configure = address.traverse(_.resolve).flatMap { ip =>
    
  • io/shared/src/test/scala/fs2/io/net/tcp/SocketSuite.scala+12 0 modified
    @@ -269,6 +269,18 @@ class SocketSuite extends Fs2Suite with SocketSuitePlatform {
           }
         }
     
    +    test("sockets are released at the end of the resource scope") {
    +      val f =
    +        Network[IO].serverResource(port = Some(port"9071")).use { case (bindAddress, clients) =>
    +          clients.foreach(_ => IO.sleep(1.second)).compile.drain.background.surround {
    +            Network[IO].client(bindAddress).use { client =>
    +              client.read(1).assertEquals(None)
    +            }
    +          }
    +        }
    +      f >> f >> f
    +    }
    +
         test("endOfOutput / endOfInput ignores ENOTCONN") {
           Network[IO].serverResource().use { case (bindAddress, clients) =>
             Network[IO].client(bindAddress).surround(IO.sleep(100.millis)).background.surround {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.