From 4b0862cc00815a47b22339d7eac7ddc3b6645bd4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 21 Apr 2026 11:26:05 +0100 Subject: [PATCH] Use constant-time comparison for remote DevTools secret Closes gh-50169 --- .../remote/server/HttpHeaderAccessManager.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManager.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManager.java index 6191f6a0b38..6780d7cd5e7 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManager.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManager.java @@ -16,6 +16,9 @@ package org.springframework.boot.devtools.remote.server; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; + import org.springframework.http.server.ServerHttpRequest; import org.springframework.util.Assert; @@ -30,19 +33,20 @@ public class HttpHeaderAccessManager implements AccessManager { private final String headerName; - private final String expectedSecret; + private final byte[] expectedSecret; public HttpHeaderAccessManager(String headerName, String expectedSecret) { Assert.hasLength(headerName, "'headerName' must not be empty"); Assert.hasLength(expectedSecret, "'expectedSecret' must not be empty"); this.headerName = headerName; - this.expectedSecret = expectedSecret; + this.expectedSecret = expectedSecret.getBytes(StandardCharsets.UTF_8); } @Override public boolean isAllowed(ServerHttpRequest request) { String providedSecret = request.getHeaders().getFirst(this.headerName); - return this.expectedSecret.equals(providedSecret); + return (providedSecret != null) + && MessageDigest.isEqual(providedSecret.getBytes(StandardCharsets.UTF_8), this.expectedSecret); } }