This is an automated email from the ASF dual-hosted git repository.

dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new bbe2a35b45 fix: docker-compose hardcoded JWT secret key allows forging 
admin authentication (#7063)
bbe2a35b45 is described below

commit bbe2a35b450b9feb3d9dc9acb69e5a6fdb6dcc61
Author: Arvin <[email protected]>
AuthorDate: Wed Sep 16 00:17:27 2026 +0800

    fix: docker-compose hardcoded JWT secret key allows forging admin 
authentication (#7063)
    
    * fix #7058: force setting SHENYU_JWT_SECRETKEY in docker-compose instead 
of shipping a public default
    
    * fix #7058: add previously distributed public JWT key to the sentinel 
denylist
    
    * fix #7058: reject the publicly-known compose JWT key with fail-fast 
validation
    
    * test #7058: java validator unit test for public compose JWT key rejection
    
    ---------
    
    Co-authored-by: aias00 <[email protected]>
    Co-authored-by: Liming Deng <[email protected]>
---
 .../org/apache/shenyu/admin/config/properties/JwtProperties.java  | 3 ++-
 .../apache/shenyu/admin/config/properties/JwtPropertiesTest.java  | 8 ++++++++
 .../java/org/apache/shenyu/common/constant/AdminConstants.java    | 6 ++++++
 .../src/main/resources/docker-compose.yaml                        | 7 +++++--
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/JwtProperties.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/JwtProperties.java
index 7ea2ed4685..ad14011734 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/JwtProperties.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/JwtProperties.java
@@ -40,7 +40,8 @@ public class JwtProperties {
 
     @PostConstruct
     private void init() {
-        if (StringUtils.isBlank(secretKey) || 
AdminConstants.JWT_DEFAULT_SECRET_KEY.equals(this.secretKey)) {
+        if (StringUtils.isBlank(secretKey) || 
AdminConstants.JWT_DEFAULT_SECRET_KEY.equals(this.secretKey)
+                || 
AdminConstants.JWT_PUBLIC_SECRET_KEY.equals(this.secretKey)) {
             throw new IllegalStateException("shenyu.jwt.secretKey is not 
configured. "
                     + "In a multi-instance Admin cluster, each instance would 
generate a different key, "
                     + "causing token verification failures. "
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/config/properties/JwtPropertiesTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/config/properties/JwtPropertiesTest.java
index bc2b747117..e81ea45137 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/config/properties/JwtPropertiesTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/config/properties/JwtPropertiesTest.java
@@ -45,6 +45,14 @@ public class JwtPropertiesTest {
                 () -> ReflectionTestUtils.invokeMethod(jwtProperties, "init"));
     }
 
+    @Test
+    public void testInitThrowsWhenSecretKeyIsPublicComposeKey() {
+        final JwtProperties jwtProperties = new JwtProperties();
+        jwtProperties.setSecretKey("please-replace-with-your-own-secret-key");
+        Assertions.assertThrows(IllegalStateException.class,
+                () -> ReflectionTestUtils.invokeMethod(jwtProperties, "init"));
+    }
+
     @Test
     public void testInitDoesNotThrowWhenSecretKeyIsConfigured() {
         final JwtProperties jwtProperties = new JwtProperties();
diff --git 
a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/AdminConstants.java
 
b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/AdminConstants.java
index a160077bd5..4f3807a3b8 100644
--- 
a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/AdminConstants.java
+++ 
b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/AdminConstants.java
@@ -308,5 +308,11 @@ public final class AdminConstants {
     public static final long TEN_SECONDS_MILLIS_TIME = 10 * 1000L;
 
     public static final String JWT_DEFAULT_SECRET_KEY = "defaultSecretKey";
+
+    /**
+     * The publicly-known JWT secret key that was previously distributed in 
the official docker-compose.yaml.
+     * Any token signed with it can be forged by anyone who reads the 
repository, so it must be rejected.
+     */
+    public static final String JWT_PUBLIC_SECRET_KEY = 
"please-replace-with-your-own-secret-key";
 }
 
diff --git 
a/shenyu-dist/shenyu-docker-compose-dist/src/main/resources/docker-compose.yaml 
b/shenyu-dist/shenyu-docker-compose-dist/src/main/resources/docker-compose.yaml
index 41d9cdeef7..ec0778f111 100644
--- 
a/shenyu-dist/shenyu-docker-compose-dist/src/main/resources/docker-compose.yaml
+++ 
b/shenyu-dist/shenyu-docker-compose-dist/src/main/resources/docker-compose.yaml
@@ -44,9 +44,12 @@ services:
     ports:
       - "9095:9095"
     environment:
-      # Required: replace with your own secure key in production.
+      # Required: generate your own secure key and export it, e.g.
+      #   openssl rand -base64 48
+      #   export SHENYU_JWT_SECRETKEY=<the-generated-value>
+      # docker compose refuses to start until SHENYU_JWT_SECRETKEY is set.
       # In a multi-instance Admin cluster, all instances must share the same 
secretKey.
-      - SHENYU_JWT_SECRETKEY=please-replace-with-your-own-secret-key
+      - SHENYU_JWT_SECRETKEY=${SHENYU_JWT_SECRETKEY:?SHENYU_JWT_SECRETKEY must 
be set. Generate one with 'openssl rand -base64 48' and export it.}
     healthcheck:
       test: [ "CMD-SHELL", "wget -q -O - 
http://shenyu-admin:9095/actuator/health | grep UP || exit 1" ]
       timeout: 2s

Reply via email to