CVE-2026-58377: Verified Reproduction
CVE-2026-58377: JeecgBoot broken access control privilege escalation
CVE-2026-58377 is verified against jeecgboot/JeecgBoot · github. Affected versions: JeecgBoot through 3.9.2 (all versions up to and including 3.9.2). Vulnerability class: Privilege Escalation. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00250.
What Is CVE-2026-58377?
CVE-2026-58377 is a high-severity broken access control vulnerability in JeecgBoot that lets an authenticated low-privileged user escalate privileges. Pruva reproduced it (reproduction REPRO-2026-00250).
CVE-2026-58377 Severity & CVSS Score
CVE-2026-58377 is rated high severity, with a CVSS base score of 8.1 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected jeecgboot/JeecgBoot Versions
jeecgboot/JeecgBoot · github versions JeecgBoot through 3.9.2 (all versions up to and including 3.9.2) are affected.
How to Reproduce CVE-2026-58377
pruva-verify REPRO-2026-00250 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00250/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-58377
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
authenticated low-privileged user JWT token (ceshi/test role, password 123456)
- POST /jeecg-boot/sys/login (ceshi)
- GET/POST/DELETE /jeecg-boot/openapi/auth/* with X-Access-Token header
How the agent worked
Root Cause and Exploit Chain for CVE-2026-58377
JeecgBoot v3.9.2 contains a broken access control vulnerability in the OpenAPI credential management module. The OpenApiAuthController (/openapi/auth/*) and OpenApiPermissionController (/openapi/permission/*) expose full CRUD endpoints for managing OpenAPI AK/SK credential pairs without any Shiro authorization annotations (@RequiresRoles or @RequiresPermissions). In contrast, the sibling OpenApiController (/openapi/*) correctly annotates its mutating endpoints with @RequiresRoles({"admin"}). Because the Shiro filter chain maps /** to the jwt filter (authentication-only, no authorization), any authenticated user — including low-privileged users with only a "test" role — can list, create, edit, and delete all OpenAPI credential pairs, with the list endpoint returning secret keys (SK) in plaintext. This enables credential theft and unauthorized invocation of the OpenAPI surface, including endpoints owned by administrator accounts.
- Package/component affected:
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiAuthController.javaandOpenApiPermissionController.java - Affected versions: JeecgBoot through 3.9.2 (commit
7df07a823fd558be857d0208ccae96342539fbc1, tagv3.9.2) - Risk level: HIGH (CVSS 4.0: 8.6)
- Consequences:
- Any authenticated low-privilege user can read all OpenAPI AK/SK credential pairs in plaintext, including those belonging to administrators.
- Low-privilege users can create, modify, and delete credential records without administrative authorization.
- Stolen credentials can be used to invoke the OpenAPI surface (
/openapi/call/**, which is mapped toanonand only checks theappkeyheader), impersonating the credential owner — including administrators.
Impact Parity
- Disclosed/claimed maximum impact: Privilege escalation — authenticated low-privilege users perform full CRUD on OpenAPI credentials, read admin secret keys in plaintext, and can invoke privileged API routes as the credential owner.
- Reproduced impact from this run: A low-privileged user (ceshi, role=test) successfully:
- Read admin's AK/SK credentials in plaintext via
GET /openapi/auth/list(ak=ak-pFjyNHWRsJEFWlu6, sk=4hV5dBrZtmGAtPdbA5yseaeKRYNpzGsS, owner=admin) - Created a new OpenAPI credential via
POST /openapi/auth/add(persisted to database) - Deleted an OpenAPI credential via
DELETE /openapi/auth/delete - Generated a new AK/SK pair via
GET /openapi/auth/genAKSK - Was correctly rejected by the protected
POST /openapi/addendpoint (has@RequiresRoles({"admin"})), confirming the authorization gap is specific toOpenApiAuthController
- Read admin's AK/SK credentials in plaintext via
- Parity:
full— all claimed CRUD operations on OpenAPI credentials were demonstrated, including plaintext secret key exposure and the negative control showing the sibling controller is properly protected. - Not demonstrated: Actual invocation of
/openapi/call/**with stolen credentials to impersonate the admin (the second root cause described in the advisory). The primary broken access control on credential management endpoints is fully proven.
Root Cause
The Shiro security configuration (ShiroConfig.java) maps all URL paths (/**) to the jwt filter, which performs authentication only (validates JWT token existence and signature). Authorization (role/permission checks) is enforced exclusively through method-level annotations such as @RequiresRoles and @RequiresPermissions.
The OpenApiAuthController at /openapi/auth/* exposes seven endpoints — GET /list, POST /add, PUT /edit, DELETE /delete, DELETE /deleteBatch, GET /queryById, and GET /genAKSK — none of which carry any Shiro authorization annotation. This means the Shiro authorization layer is never triggered for these endpoints; any user who passes JWT authentication can access them.
In contrast, the sibling OpenApiController at /openapi/* correctly annotates its mutating endpoints (/add, /edit, /delete, /deleteBatch) with @RequiresRoles({"admin"}), which triggers Shiro's AuthorizationAttributeSourceAdvisor and enforces that only users with the "admin" role can perform those operations.
The OpenApiPermissionController at /openapi/permission/* has the same absence of authorization annotations on its POST /add and GET /getOpenApi endpoints.
Additionally, the /openapi/call/** path is mapped to anon (no authentication required at all), and the OpenApiController.call() method only reads the appkey header to look up the auth record without verifying the secret key signature, enabling unauthorized API invocation with stolen credentials.
Fix commit: Not yet publicly available in the main branch as of this analysis. The fix would involve adding @RequiresRoles({"admin"}) annotations to all mutating endpoints in OpenApiAuthController and OpenApiPermissionController, and implementing SK signature verification in the call() method.
Reproduction Steps
- Reference:
bundle/repro/reproduction_steps.sh - What the script does:
- Resolves the JeecgBoot v3.9.2 repository from the prepared project cache
- Installs JDK 17, Maven, Redis, and MariaDB if not present
- Starts MariaDB and Redis, creates the
jeecg-bootdatabase, and imports the seed SQL (which includes an admin-owned OpenAPI credential) - Uses the pre-built
jeecg-system-start-3.9.2.jar(or builds it with Maven if not present) - Starts the JeecgBoot Spring Boot application with login captcha disabled (
--jeecg.firewall.enableLoginCaptcha=false) - Logs in as the low-privileged user
ceshi(role:test, password:123456) and obtains a JWT token - Calls
GET /openapi/auth/listwith the low-priv JWT to read all AK/SK credentials in plaintext - Calls
POST /openapi/auth/addto create a credential as the low-priv user (verified in database) - Calls
DELETE /openapi/auth/deleteto delete a credential as the low-priv user - Calls
GET /openapi/auth/genAKSKto generate an AK/SK pair as the low-priv user - Negative control: Calls
POST /openapi/add(which has@RequiresRoles({"admin"})) and confirms it rejects the low-priv user with "Subject does not have role [admin]" - Admin positive control: Logs in as admin and confirms admin can access
POST /openapi/add - Writes the runtime manifest with all proof artifacts
- Expected evidence of reproduction:
artifacts/http/openapi_auth_list_response.json— showssuccess: truewith admin's AK/SK in plaintextartifacts/http/openapi_auth_add_response.json— showssuccess: true(low-priv user created credential)artifacts/http/openapi_auth_delete_response.json— showssuccess: true(low-priv user deleted credential)artifacts/http/openapi_auth_genAKSK_response.json— showssuccess: truewith generated AK/SK pairartifacts/http/openapi_add_negcontrol_response.json— showssuccess: falsewith "Subject does not have role [admin]"artifacts/http/openapi_add_admin_response.json— showssuccess: true(admin can access protected endpoint)
Evidence
Log file locations:
bundle/logs/reproduction_steps.log— full script execution logbundle/logs/jeecgboot_app.log— JeecgBoot application startup and runtime logbundle/artifacts/http/*.json— HTTP request/response captures for each proof
Key excerpts proving reproduction:
PROOF 1 — Low-priv user reads admin's AK/SK in plaintext (
openapi_auth_list_response.json):{ "success": true, "code": 200, "result": { "records": [{ "id": "1922164194775056386", "name": "scott", "ak": "ak-pFjyNHWRsJEFWlu6", "sk": "4hV5dBrZtmGAtPdbA5yseaeKRYNpzGsS", "systemUserId": "e9ca23d68d884d4ebb19d07889727dae", "systemUserId_dictText": "admin" }] } }NEGATIVE CONTROL — Protected endpoint rejects low-priv user (
openapi_add_negcontrol_response.json):{ "success": false, "message": "Subject does not have role [admin]", "code": 500 }Environment details:
- JeecgBoot v3.9.2 (Spring Boot 3.5.5, Java 17.0.19)
- MariaDB 11.8.6, Redis 8.0.5
- Low-priv user: ceshi (role: test, tenant: 1001)
- Admin user: admin (role: admin, tenant: 1000)
- Application context path: /jeecg-boot, port 8080
Recommendations / Next Steps
- Fix approach: Add
@RequiresRoles({"admin"})annotations to all mutating endpoints inOpenApiAuthController(/add,/edit,/delete,/deleteBatch) andOpenApiPermissionController(/add). Consider whether the/list,/queryById, and/genAKSKendpoints should also be admin-only or restricted to credentials owned by the requesting user. - Additional fix: Implement secret key (SK) signature verification in
OpenApiController.call()to prevent unauthorized API invocation with stolen AK-only credentials. - Upgrade guidance: Upgrade to a version that includes the fix once available. In the interim, restrict access to
/openapi/auth/**and/openapi/permission/**via reverse proxy rules (e.g., nginx) to admin-only users. - Testing recommendations: Add integration tests that verify non-admin users receive 403/510 responses when accessing OpenAPI credential management endpoints. Add tests that verify SK signature validation in the call endpoint.
Additional Notes
- Idempotency confirmation: The script was run twice consecutively, both runs succeeded with exit code 0 and all 4 proofs confirmed. The script drops and recreates the database on each run, ensuring a clean state.
- Captcha handling: Login captcha was disabled via
--jeecg.firewall.enableLoginCaptcha=falseSpring Boot argument to enable automated login. This does not affect the vulnerability — the captcha is an authentication-layer control, while the vulnerability is in the authorization layer. - Port conflict: Apache2 was found occupying port 8080 in the test environment; the script kills it before starting JeecgBoot.
- Seed data: The seed SQL includes one admin-owned OpenAPI credential (
name: scott,ak: ak-pFjyNHWRsJEFWlu6,sk: 4hV5dBrZtmGAtPdbA5yseaeKRYNpzGsS,systemUserId: admin), which serves as the target credential for the privilege escalation proof.
CVE-2026-58377 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.
Artifacts and Evidence for CVE-2026-58377
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-58377
FAQ: CVE-2026-58377
How does the JeecgBoot privilege escalation work?
Which JeecgBoot versions are affected by CVE-2026-58377?
How severe is CVE-2026-58377?
How can I reproduce CVE-2026-58377?
References for CVE-2026-58377
Authoritative sources for CVE-2026-58377 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.