CVE-2026-23958: Verified Reproduction
CVE-2026-23958: DataEase: authentication bypass via password-derived HMAC JWT signing key
CVE-2026-23958 is verified against dataease · github. Affected versions: <= v2.10.20. Fixed in v2.10.21. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00168.
What Is CVE-2026-23958?
CVE-2026-23958 is a high-severity authentication-bypass vulnerability in DataEase, a Spring Boot data-visualization platform, caused by signing authentication JWTs with a key derived from the admin password. Pruva reproduced it (reproduction REPRO-2026-00168).
CVE-2026-23958 Severity & CVSS Score
CVE-2026-23958 is rated critical severity, with a CVSS base score of 9.8 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected dataease Versions
dataease · github versions <= v2.10.20 are affected.
How to Reproduce CVE-2026-23958
pruva-verify REPRO-2026-00168 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00168/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-23958
- Vulnerable
v2.10.10 - Fixed
v2.10.21
How the agent worked
Root Cause and Exploit Chain for CVE-2026-23958
DataEase signs its authentication JWTs with an HMAC-SHA256 key derived from the admin password. In vulnerable versions, the CommunityTokenFilter uses getPwd() (which returns the raw password hash) as the JWT verification secret. Because the default admin password is the well-known constant DataEase@123456, an unauthenticated attacker can compute MD5("DataEase@123456"), forge a JWT with claims {uid:1, oid:1}, and present it in the X-DE-TOKEN header to access any protected REST endpoint as the admin user.
- Package/Component:
io.dataease.auth.filter.CommunityTokenFilter(sdk/common) andio.dataease.xpack.permissions.login.bo.LoginUserCacheBO(xpack-permission) - Affected versions: Docker images up to and including v2.10.10 are demonstrably vulnerable. Git commit analysis shows the fix (
getPwd→getSecret) was already merged by v2.10.20, but the ticket incorrectly labels v2.10.20 as vulnerable. - Risk level: High — unauthenticated remote attacker can impersonate the admin user.
- Consequences: Full admin takeover via forged JWT, enabling subsequent exploitation of authenticated endpoints.
Root Cause
In the CommunityTokenFilter.doFilter method, when the application is running with an active loginServer bean (the standard Docker image configuration), the filter reaches the else branch and derives the JWT secret from the user cache object:
Object apisixCacheManage = CommonBeanFactory.getBean("apisixCacheManage");
Method method = DeReflectUtil.findMethod(apisixCacheManage.getClass(), "userCacheBO");
Object o = ReflectionUtils.invokeMethod(method, apisixCacheManage, userId);
Method pwdMethod = DeReflectUtil.findMethod(o.getClass(), "getPwd"); // vulnerable
Object pwdObj = ReflectionUtils.invokeMethod(pwdMethod, o);
secret = pwdObj.toString();
In the vulnerable code (getPwd), secret is simply the user's password hash (504c8c8dfcbbe5b50d676ad65ef43909 for the default admin). This is trivially derivable by anyone who knows the default password. The fix changes getPwd to getSecret, which concatenates the password hash with the per-installation RSA public key, making the secret unpredictable and no longer derivable from public information alone.
Fix commit: cac165ee84bb296184b9be6f5fa695af0344fa05 ("fix: JWT Token 漏洞", 2025-12-25). This commit is already present in git tag v2.10.20 and in Docker images v2.10.20+.
Reproduction Steps
- Run
repro/reproduction_steps.sh - The script:
- Starts a MySQL 8 container and a DataEase v2.10.10 container (vulnerable)
- Waits for the API to respond on
http://127.0.0.1:8100 - Baselines an anonymous request to
/de2api/user/personInfo→ expects 401 - Forges a JWT with
secret = MD5("DataEase@123456")and sends it asX-DE-TOKEN→ expects 200 - Stops the vulnerable app but preserves the MySQL data
- Starts a DataEase v2.10.21 container against the same MySQL data
- Replays the identical forged JWT → expects 401 with
DE-GATEWAY-FLAGheader
- Expected evidence:
logs/vulnerable_attack_response.txtshows HTTP 200logs/fixed_attack_response.txtshows HTTP 401 andDE-GATEWAY-FLAG: The Token's Signature resulted invalid...
Evidence
logs/repro_run1.log— first successful execution ofreproduction_steps.shlogs/repro_run2.log— second successful execution (idempotency confirmed)logs/vulnerable_transcript.txt— summary of v2.10.10 test resultslogs/fixed_transcript.txt— summary of v2.10.21 test resultslogs/vulnerable_attack_response.txt— raw HTTP response showing 200 on forged JWTlogs/fixed_attack_response.txt— raw HTTP response showing 401 +DE-GATEWAY-FLAG
Key excerpts from v2.10.10 (vulnerable):
HTTP/1.1 200
X-DE-EXECUTE-VERSION: 2.10.10
...
{"code":60003,"msg":"缺少许可证","data":null}
(The 200 status proves the JWT signature was accepted; the downstream "missing license" error is irrelevant to the auth bypass.)
Key excerpts from v2.10.21 (fixed):
HTTP/1.1 401
X-DE-EXECUTE-VERSION: 2.10.21
DE-GATEWAY-FLAG: The%20Token%27s%20Signature%20resulted%20invalid%20when%20verified%20using%20the%20Algorithm%3A%20HmacSHA256
Recommendations / Next Steps
- Upgrade to DataEase v2.10.20 or later. The fix commit is already present in those builds.
- Rotate secrets: If running an older vulnerable build, change the admin password and restart the application so that any cached JWT secret is regenerated.
- Additional hardening: Remove the fallback MD5-based secret derivation in
SubstituleLoginConfigentirely, or enforce a randomly generated community-edition signing key at first boot. - Regression testing: Add an integration test that attempts to authenticate with a JWT signed using only
MD5(default_password)and asserts 401.
Additional Notes
- Idempotency:
reproduction_steps.shwas executed twice consecutively with identical results (HTTP 200 on v2.10.10, HTTP 401 on v2.10.21). - Version discrepancy: The ticket specifies v2.10.20 as vulnerable and v2.10.21 as fixed. However, binary analysis of the official Docker images shows that v2.10.20 already contains the
getSecret()fix. The last vulnerable official Docker image we could identify is v2.10.10, which still usesgetPwd(). The reproduction script therefore uses v2.10.10 as the vulnerable baseline and v2.10.21 as the fixed baseline to ensure the vulnerability is actually demonstrated at runtime. - Environment: Docker 27.x, Ubuntu 22.04 sandbox, images pulled from
registry.cn-qingdao.aliyuncs.com/dataease/.
CVE-2026-23958 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Unknown error
Unknown error
git clone --depth=50 https://github.com/dataease/dataease.git /tmp/dataease && cd /tmp/dataease && git log --oneline --all | head -30{"cwd":"/root/.pruva/runs/cve-2026-23958_20260525-214431","duration_ms":5886,"exit_code":0,"stderr":"Cloning into '/tmp/dataease'...\nUpdating files: 35% (2296/6378)\rUpdating files: 36% (2297/6378)\rUpdating files: 37% (2360/6378)\rUpdating files: 38% (2424/6378)\rUpdating files: 39% (2488/6378)\rUpdating files: 40% (2552/6378)\rUpdating files: 41% (2615/6378)\rUpdating files: 42% (2679/6378)\rUpdating files: 43% (2743/6378)\rUpdating files: 44% (2807/6378)\rUpdating files: 45% (2871/6378)\rUpdating files: 46% (2934/6378)\rUpdating files: 47% (2998/6378)\rUpdating files: 48% (3062/6378)\rUpdating files: 49% (3126/6378)\rUpdating files: 50% (3189/6378)\rUpdating files: 51% (3253/6378)\rUpdating files: 52% (3317/6378)\rUpdating files: 53% (3381/6378)\rUpdating files: 54% (3445/6378)\rUpdating files: 55% (3508/6378)\rUpdating files: 56% (3572/6378)\rUpdating files: 57% (3636/6378)\rUpdating files: 58% (3700/6378)\rUpdating files: 59% (3764/6378)\rUpdating files: 60% (3827/6378)\rUpdating files: 61% (3891/6378)\rUpdating files: 62% (3955/6378)\rUpdating files: 63% (4019/6378)\rUpdating files: 64% (4082/6378)\rUpdating files: 65% (4146/6378)\rUpdating fil… [truncated]Artifacts and Evidence for CVE-2026-23958
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-23958
Upgrade dataease · github to v2.10.21 or later.
FAQ: CVE-2026-23958
How does the DataEase JWT forgery attack work?
Which DataEase versions are affected by CVE-2026-23958, and where is it fixed?
How severe is CVE-2026-23958?
How can I reproduce CVE-2026-23958?
References for CVE-2026-23958
Authoritative sources for CVE-2026-23958 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.