From aa5089e3f68e6c68f59faa820ac25a35e01b8abe Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 22 Apr 2026 20:50:44 +0100 Subject: [PATCH] Improve handling of malformed LiveReload request header Closes gh-50142 --- .../devtools/livereload/ConnectionInputStream.java | 11 +++++++++-- .../livereload/ConnectionInputStreamTests.java | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionInputStream.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionInputStream.java index 7bbaffe466e..21dc90c2c75 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionInputStream.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionInputStream.java @@ -31,6 +31,8 @@ class ConnectionInputStream extends FilterInputStream { private static final int BUFFER_SIZE = 4096; + private static final int MAX_HEADER_SIZE = 8192; + ConnectionInputStream(InputStream in) { super(in); } @@ -45,11 +47,16 @@ class ConnectionInputStream extends FilterInputStream { String readHeader() throws IOException { byte[] buffer = new byte[BUFFER_SIZE]; StringBuilder content = new StringBuilder(BUFFER_SIZE); - while (content.indexOf(HEADER_END) == -1) { + while (content.indexOf(HEADER_END) == -1 && content.length() < MAX_HEADER_SIZE) { int amountRead = checkedRead(buffer, 0, BUFFER_SIZE); content.append(new String(buffer, 0, amountRead)); } - return content.substring(0, content.indexOf(HEADER_END)); + + int endIndex = content.indexOf(HEADER_END); + if (endIndex == -1) { + throw new IOException("Malformed header"); + } + return content.substring(0, endIndex); } /** diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/ConnectionInputStreamTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/ConnectionInputStreamTests.java index b89edae3e1a..2cc3bae701f 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/ConnectionInputStreamTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/ConnectionInputStreamTests.java @@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Random; import org.junit.jupiter.api.Test; @@ -47,6 +48,14 @@ class ConnectionInputStreamTests { assertThat(inputStream.readHeader()).isEqualTo(header); } + @Test + void readHeaderThrowsWhenHeaderIsMalformed() { + byte[] header = new byte[10000]; + new Random().nextBytes(header); + ConnectionInputStream inputStream = new ConnectionInputStream(new ByteArrayInputStream(header)); + assertThatIOException().isThrownBy(inputStream::readHeader).withMessage("Malformed header"); + } + @Test void readFully() throws Exception { byte[] bytes = "the data that we want to read fully".getBytes();