One Hundred Records in Two Days: JeecgBoot’s Second Wave Turns to Enterprise Messaging Integrations

Yesterday we documented seventy-six contiguous JeecgBoot CVEs, CVE-2026-108605 through CVE-2026-108680, all missing-authorization findings against version 3.9.5 with no fixed version anywhere. Today NVD published the second wave: twenty-four more, CVE-2026-108866 through CVE-2026-108888 contiguous plus CVE-2026-108891, all timestamped 11 October 2026 between 15:16:53Z and 15:16:56Z. That brings the two-day total against this one product to one hundred CVE records. The ranges are disjoint and the methodology is identical, so this is a continuation of the same disclosure, not a coincidence of numbering.

The shape is unchanged. Every record carries disclosure@vulncheck.com as its source and Received as its NVD status. Twenty-three of the twenty-four are CWE-862 missing authorization at CVSS 4.0 5.3 (CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N and close variants); the twenty-fourth is the highest-scored of the batch and the one we lead with. The affected ceiling on all twenty-four is “through 3.9.5”. The newest JeecgBoot release is still v3.9.5, published 27 August 2026, and the repository’s main branch was last pushed on 22 September. There is still no version to upgrade to.

The highest score redirects the company’s chat integrations

CVE-2026-108883 — 7.1 high, CWE-862, CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N. The editThirdAppConfig handler lets any authenticated user modify third-party application configurations: the client ID, client secret, agent ID and corporate ID of the DingTalk, WeCom and Feishu integrations. An attacker replaces those values with ones pointing at an attacker-controlled application, and directory synchronisation plus messaging traffic for those platforms follows. This is the integrity-heavy finding of the batch, and the score reflects it — it is the only record of the twenty-four above 5.3.

Its neighbours show what “missing authorization” means when it lands on identity infrastructure rather than on content. CVE-2026-108866 exposes queryUserAuths: supply an arbitrary userId and receive that account’s complete permission set, which doubles as an administrator-enumeration oracle. CVE-2026-108867 does the same for role assignments via getUserRoleSetById, explicitly without the system:user:queryUserRole permission the endpoint’s own name implies. CVE-2026-108870 and CVE-2026-108871 go one step further and let a low-privileged caller overwrite role and department data rules — clearing the row-level filters that decide which records other roles can read. And CVE-2026-108891 returns other users’ details wholesale: real names, usernames, emails, phone numbers, birthdays, employee numbers, department paths and posts.

We read queryUserAuths first-hand at the pinned release commit e3b9dc0a, the v3.9.5 tag the advisories reference:

@GetMapping("/queryUserAuths")
public Set<String> queryUserAuths(@RequestParam("userId") String userId){
    return sysUserService.getUserPermissionsSet(userId);
}

No @RequiresPermissions, no ownership check, one line between the caller’s parameter and another account’s permission set. We then read the same file at main HEAD. It is byte-identical — 1,155 lines, no difference. This one is unfixed everywhere, including on the branch.

The AI module gains three more, and the pattern repeats exactly

Three of the twenty-four land in the Airag AI module, taking its running total to twenty-five of the hundred. CVE-2026-108878 lets a low-privileged caller read any AI application’s configuration through the AiragAppController queryById handler — system prompts, memory prompts, model IDs, knowledge base IDs and plugin bindings — with application IDs enumerable from the unguarded /airag/app/listDict endpoint. CVE-2026-108877 is the logical deletion of any user’s prompt template through DELETE /airag/prompts/delete, with template IDs obtainable from the unguarded list endpoint. CVE-2026-108879 is the only CWE-639 of the wave: the AiragBaseApiController getChatVariable handler reads other users’ stored AI chat variables out of Redis on the strength of a caller-supplied username parameter.

We read all three at the release commit. The prompts delete handler at e3b9dc0a:

@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
    airagPromptsService.removeById(id);
    return Result.OK("删除成功!");
}

And the chat-variable reader, in full — the whole controller is seventy-six lines of unannotated parameter forwarding:

@PostMapping("/airag/api/getChatVariable")
public String getChatVariable(
        @RequestParam("appId") String appId,
        @RequestParam("username") String username,
        @RequestParam("name") String name
) {
    return airagBaseApi.getChatVariable(appId, username, name);
}

Then the main-HEAD comparison, which is the part of this story we find most instructive. The prompts delete handler at main HEAD now reads:

@DeleteMapping(value = "/delete")
@RequiresPermissions("airag:prompts:delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {

The annotation is there, the file has grown from 207 to 220 lines and now carries thirteen @RequiresPermissions annotations — the September cleanup commit (21facc013906, 11 September) that we traced in yesterday’s briefing. But AiragBaseApiController.java at main HEAD is byte-identical to the release commit: same seventy-six lines, same caller-controlled (appId, username, name) triple, no annotation. So within three CVEs in the same module, published in the same three seconds, one exhibits the exact “fix exists only in main, no release ships it” shape from yesterday’s piece, and the other two are not fixed anywhere at all.

One observation we raise as our own, not the advisory’s: the same file exposes setChatVariable taking the identical (appId, username, name) triple plus a value. The CVE names the read; the write sits beside it with the same parameters and the same absence of authorization. We did not test it and make no claim beyond what the code shows — but a chat-memory read primitive and a chat-memory write primitive sharing one unguarded parameter triple is worth stating plainly so whoever remediates 108879 remediates both.

The rest of the wave, and what it says about the first one

The remaining records fill out the same access-control debt across user, department, tenant and messaging management: batchEditUsers (108872), department modification plus assigning or removing department heads (108873, 108874), user-group membership (108875), putCancelQuit (108876), dictionary editing by low-app ID (108880), cross-tenant pack membership reads that disclose administrator usernames, real names, phones and departments for fixed pack codes like superAdmin (108881), position membership removal (108882), message-template and message deletion (108884, 108885), username-subtree reads (108886), comment and department-role exports (108887, 108888), and templated announcement publishing with a forgeable fromUser across WebSocket, DingTalk, WeCom, Feishu and UniPush channels (108868, 108869).

Two process details are worth recording. First, the proof-of-concept repository (AnkesKasty/cve-request-poc) already contains per-finding scripts for this wave — poc_sys_api_query_user_auths.py, poc_airag_prompts_delete.py, poc_caller_identity_subjects.py, poc_sys_thirdapp_edit_config_post.py among them — in a repository created on 10 October at 14:31:43Z and last pushed at 14:47Z, roughly a full day before the NVD records appeared. The disclosure arrived with working scripts, pinned source lines and no version to upgrade to, exactly as in wave one. Second, a Brave search over the new CVE identifiers returns only automated aggregators — no analytical coverage, and nobody has yet connected the September annotation commit to the three Airag records it partially remediates.

The editorial reading is the same one we offered yesterday, sharpened. Nothing here is an AI-specific vulnerability class: no prompt injection, no model extraction, no tool-call confusion. It is CWE-862 applied to every object the console manages, and the objects that now hold prompts, retrieval corpora, MCP credentials and chat memory inherited the console’s access-control debt wholesale. What the second wave adds is the enterprise-integration consequence — the finding with the highest score is not a read of someone else’s data but a rewrite of where the company’s directory sync and messaging go — and a cleaner measurement of the remediation gap: of the three new AI-module findings we checked line by line, one is fixed on a branch nobody can install, and two are not fixed at all.

Verification note. All CVE identifiers, CVSS 4.0 base scores and vectors, CWE assignments, publication timestamps (15:16:53Z–15:16:56Z on 11 October 2026), NVD status values and the assigning source (disclosure@vulncheck.com) were read first-hand from the NVD 2.0 API. Affected ceilings, newest-release tag and date (v3.9.5, 27 August 2026), default-branch identity and last-push timestamp (main, 22 September 2026) came from the GitHub API. Every source excerpt — queryUserAuths, the Airag prompts delete handler at release and at main HEAD, and AiragBaseApiController at both revisions — was read directly from the JeecgBoot repository at commit e3b9dc0a and at main HEAD via raw file fetches, and is quoted verbatim; the byte-identical comparisons were computed with diff. The September cleanup commit (21facc013906) and its contents were established in our wave-one briefing. PoC filenames, repository creation and push timestamps came from the GitHub API; no proof-of-concept was executed and no request was sent to any JeecgBoot instance. The observation about setChatVariable, the two-day total of one hundred records, and the closing argument are our editorial analysis. We found no evidence of exploitation and do not imply any.

Sources: