Atlassian Confluence is one of the most widely deployed enterprise wiki and collaboration platforms, sitting at the heart of corporate knowledge bases, technical documentation, and internal processes. That centrality makes it a high-value target: a compromised Confluence instance often contains source code snippets, infrastructure credentials, internal API keys, and sensitive business data embedded directly in page content. Two critical OGNL injection vulnerabilities — CVE-2022-26134 and the even more severe CVE-2023-22527 (CVSS 10.0) — gave unauthenticated attackers full remote code execution on unpatched servers, and both remain actively exploited in the wild. Beyond unpatched CVEs, misconfigured anonymous space access, REST API token abuse, and Jira integration credential exposure round out the Confluence attack surface. This guide covers systematic Confluence security assessment for penetration testers and security teams.
Freshly installed Confluence instances expose a setup wizard that, if left incomplete or accessible after setup, can allow an attacker to create a new administrator account or reveal internal configuration details. The setup wizard is accessible at /setup/setupadministrator.action and related endpoints — on an already-configured instance, any response other than a redirect to the login page warrants investigation.
# Check for exposed setup wizard — should redirect (302) on configured instances
curl -s -o /dev/null -w "%{http_code}" \
http://confluence.example.com/setup/setupadministrator.action
# 200 = setup wizard still accessible (critical misconfiguration)
# 302 = properly configured
# Check additional setup endpoints
for path in \
"/setup/setupstart.action" \
"/setup/finishsetup.action" \
"/setup/setupdbchoice.action" \
"/bootstrap/firstrun.action"; do
CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"http://confluence.example.com${path}")
echo "${CODE} ${path}"
done
Beyond the setup wizard, early Confluence versions shipped with no default administrative credentials — the admin account is created during setup. However, many organizations use weak passwords such as admin, confluence, or the company name for the initial administrator. Test authentication at /login.action and observe whether the response includes a Confluence version banner in HTTP headers or page source, which directly informs which CVEs apply.
# Extract version from login page or HTTP headers
curl -s -I http://confluence.example.com/login.action | grep -i "x-confluence\|server\|atlassian"
# Version also visible in meta tags
curl -s http://confluence.example.com/login.action \
| grep -i "version\|ajs-version-number\|build-number" | head -5
CVE-2023-22527 is a template injection vulnerability in Confluence Data Center and Server versions 8.0.x through 8.5.3 (and some 8.6.x and 8.7.x versions). It allows unauthenticated remote code execution via OGNL (Object-Graph Navigation Language) expression injection in the template parameter of the /_/;/WEB-INF/web.xml endpoint path traversal chain. Atlassian rated this CVSS 10.0 — the maximum possible score — and it was widely exploited within days of disclosure in January 2024.
Affected versions: Confluence Data Center and Server 8.0.0 – 8.5.3. Versions 7.x and earlier are not affected. Confluence Cloud is not affected.
| Version Branch | Affected Range | Fixed Version |
|---|---|---|
| 8.5.x (LTS) | 8.5.0 – 8.5.3 | 8.5.4 or later |
| 8.4.x | 8.4.0 – 8.4.5 | Upgrade to 8.5.4+ |
| 8.3.x | 8.3.0 – 8.3.4 | Upgrade to 8.5.4+ |
| 8.2.x | 8.2.0 – 8.2.3 | Upgrade to 8.5.4+ |
| 8.1.x | 8.1.0 – 8.1.4 | Upgrade to 8.5.4+ |
| 8.0.x | 8.0.0 – 8.0.4 | Upgrade to 8.5.4+ |
For detection purposes (without triggering active exploitation), check whether the target version falls in the vulnerable range and probe for the characteristic endpoint response pattern. A safe version-based detection approach:
# Safe detection: version check only (no payload execution)
# Extract the version number and compare against affected ranges
VERSION=$(curl -s "http://confluence.example.com/login.action" \
| grep -o 'ajs-version-number" content="[0-9.]*"' \
| grep -o '[0-9.]*')
echo "Detected Confluence version: ${VERSION}"
# Check if endpoint structure is present (indicator of 8.x, not exploit)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "http://confluence.example.com/template/aui/text-inline.vm" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "queryString=x")
echo "Template endpoint response: ${HTTP_CODE}"
# 200 on an 8.x instance = endpoint present, check version for exploitability
# 404 = not present or patched path
# For authorized testing environments: nuclei template is the standard approach
# nuclei -t cves/2023/CVE-2023-22527.yaml -u http://confluence.example.com
The vulnerability exploits a server-side template injection path where OGNL expressions in the queryString parameter are evaluated without sanitization. In exploitation, attackers achieve code execution by injecting expressions such as @java.lang.Runtime@getRuntime().exec(). Patch immediately — there is no workaround other than upgrading or taking the instance offline.
CVE-2022-26134 preceded CVE-2023-22527 and affected all Confluence Server and Data Center versions before 7.4.17, 7.13.7, 7.14.3, 7.15.2, 7.16.4, 7.17.4, and 7.18.1. It allowed unauthenticated remote code execution via OGNL injection in HTTP request URI components and was actively exploited as a zero-day before Atlassian issued patches in June 2022. Both CVE-2022-26134 and CVE-2023-22527 share the same root cause: unsafe OGNL evaluation in the Confluence template and action processing layer.
# CVE-2022-26134 — detection via URI-based OGNL injection indicator
# The vulnerability triggers via specially crafted URIs like:
# GET /%24%7B%40java.lang.Runtime%40getRuntime%28%29.exec%28...%29%7D/
# Safe detection: check for the vulnerable endpoint pattern
# Look for Confluence version in the 7.x pre-patch range
VERSION_CHECK=$(curl -sk "https://confluence.example.com/rest/api/space" \
-o /dev/null -w "%{http_code}")
echo "REST API accessible: ${VERSION_CHECK}"
# Check Server header for version disclosure
curl -skI "https://confluence.example.com/" \
| grep -i "x-confluence-request-time\|atl-token\|server"
# For authorized testing: nuclei detection template
# nuclei -t cves/2022/CVE-2022-26134.yaml -u https://confluence.example.com
# Affected version ranges to flag during assessment:
# All versions before: 7.4.17 / 7.13.7 / 7.14.3 / 7.15.2 / 7.16.4 / 7.17.4 / 7.18.1
Confluence exposes a comprehensive REST API at /rest/api/ that allows programmatic access to spaces, pages, attachments, and user data. Personal Access Tokens (PATs) — also called API tokens in Confluence Cloud — are long-lived bearer tokens that bypass the standard session authentication flow and are frequently found hardcoded in CI/CD pipelines, automation scripts, and developer dotfiles. A single leaked PAT provides access to everything the associated user can read, including restricted spaces.
# Test API token validity and retrieve authenticated user info
TOKEN="your-api-token-here"
CONFLUENCE_URL="https://confluence.example.com"
# Confluence Cloud — basic auth with API token (email:token)
curl -s -u "user@example.com:${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/space?limit=50" \
| python3 -m json.tool | grep -E '"key"|"name"|"type"'
# Confluence Server/DC — Personal Access Token (Bearer)
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/space?limit=50" \
| python3 -m json.tool | grep -E '"key"|"name"|"type"'
# Enumerate all pages in a space (replace SPACE_KEY with discovered key)
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content?spaceKey=SPACE_KEY&limit=100&expand=version,body.storage" \
| python3 -m json.tool
# Search all content for sensitive keywords
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content/search?cql=text+%7E+%22password%22&limit=25" \
| python3 -m json.tool | grep -E '"title"|"_links"'
# Search for credentials and secrets in page content
for keyword in "password" "secret" "api_key" "aws_access" "private_key" "token" "credentials"; do
echo "=== Searching for: ${keyword} ==="
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content/search?cql=text+%7E+%22${keyword}%22&limit=5" \
| python3 -m json.tool | grep '"title"'
done
# List all attachments (may include config files, keystores, .env files)
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content?type=attachment&limit=100" \
| python3 -m json.tool | grep -E '"title"|"mediaType"'
The Confluence Query Language (CQL) used in the content search endpoint is particularly powerful for an attacker: a single query can surface every page containing the word "password" or "secret" across all accessible spaces. Treat Confluence API tokens with the same sensitivity as production database credentials — they often provide access to exactly that.
Confluence supports anonymous access at both the global and per-space level. When Allow Anonymous Access to the Site is enabled globally and individual spaces inherit this setting (or are explicitly set to public), sensitive internal documentation becomes accessible without authentication. This is one of the most common high-impact findings in enterprise Confluence assessments — particularly in organizations that migrated from on-premises to Data Center and inadvertently carried over permissive legacy configurations.
# Test anonymous access — no credentials provided
curl -s "http://confluence.example.com/rest/api/space" \
| python3 -m json.tool | grep -E '"key"|"name"|"type"'
# Non-empty results without auth = anonymous access enabled globally
# List all publicly accessible spaces
curl -s "http://confluence.example.com/rest/api/space?limit=100" \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
spaces = data.get('results', [])
print(f'Anonymous-accessible spaces: {len(spaces)}')
for s in spaces:
print(f\" [{s.get('type','?')}] {s.get('key','?')} — {s.get('name','?')}\")
"
# Attempt to read page content without authentication
curl -s "http://confluence.example.com/rest/api/content?limit=25" \
| python3 -m json.tool | grep -E '"title"|"spaceKey"'
# Check global permissions endpoint (may expose permission matrix)
curl -s "http://confluence.example.com/rest/api/space/_private/permissions" \
-o /dev/null -w "HTTP %{http_code}\n"
# Enumerate space permissions for a specific space
curl -s "http://confluence.example.com/rest/api/space/SPACE_KEY/permission" \
| python3 -m json.tool | grep -E '"type"|"subjects"'
Beyond direct API access, anonymous users on a misconfigured instance can use Confluence's built-in search to discover content across all public spaces. Even "internal" spaces with no login requirement regularly contain architecture diagrams, runbooks, infrastructure passwords, and sensitive meeting notes.
The Confluence REST API exposes user search functionality that does not require elevated privileges and — depending on configuration — may be accessible to all authenticated users or even anonymously. The /rest/api/user/search endpoint accepts partial username strings and returns matching user objects including email addresses, display names, and account identifiers. This enables rapid directory harvesting for subsequent credential attacks or social engineering campaigns.
# User enumeration via REST API search
CONFLUENCE_URL="https://confluence.example.com"
# Anonymous user enumeration attempt (works on misconfigured instances)
curl -s "${CONFLUENCE_URL}/rest/api/user/search?username=a&limit=200" \
| python3 -m json.tool | grep -E '"username"|"displayName"|"email"'
# Authenticated enumeration — iterate alphabet to harvest all users
for letter in {a..z}; do
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/user/search?username=${letter}&limit=50" \
| python3 -c "
import json, sys
data = json.load(sys.stdin)
for u in data:
print(u.get('username',''), u.get('displayName',''), u.get('email',''))
" 2>/dev/null
done | sort -u
# Get current user info (validates token and reveals account details)
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/user/current" \
| python3 -m json.tool
# Enumerate group memberships
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/group?limit=50" \
| python3 -m json.tool | grep '"name"'
# List members of the confluence-administrators group
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/group/confluence-administrators/member?limit=50" \
| python3 -m json.tool | grep -E '"username"|"displayName"'
Confluence also leaks user information through the /rest/api/content endpoint's history and version expansion parameters, which expose the usernames of everyone who has ever edited a page. Cross-referencing page authors with the user search results provides a highly accurate view of the full user directory without explicitly querying user endpoints.
Confluence macros are executable components embedded in page content using the {macro-name:parameter=value} syntax. Certain macro types — particularly the HTML macro, Script macro, and third-party macros from the Atlassian Marketplace — execute code in the context of the Confluence server or user's browser, creating stored XSS and server-side injection vectors. The HTML macro is disabled by default precisely because it allows arbitrary HTML and JavaScript injection into pages; enabling it is a critical misconfiguration frequently seen in older instances.
# Test whether the HTML macro is enabled (stored XSS vector)
# In an authorized test: create a page with HTML macro content and check execution
# Detect via API: search for pages containing HTML macro markup
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content/search?cql=type%3Dpage+AND+text+%7E+%22%3Chtml%3E%22&limit=10" \
| python3 -m json.tool | grep '"title"'
# Check installed plugins/apps (requires admin access)
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/plugins/1.0/" \
| python3 -m json.tool | grep -E '"name"|"version"|"enabled"' | head -40
# List user-installed apps specifically
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/plugins/1.0/?os_authType=basic" \
-u "admin:password" \
| python3 -m json.tool | grep -E '"vendor"|"name"|"enabled"'
# Script macro detection — look for pages using scripting macros
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content/search?cql=text+%7E+%22scriptrunner%22+OR+text+%7E+%22groovy%22&limit=10" \
| python3 -m json.tool | grep '"title"'
Third-party plugins such as ScriptRunner for Confluence introduce Groovy script execution capabilities. If a low-privilege user can create or edit pages containing ScriptRunner macros on a misconfigured instance, they can execute arbitrary Groovy code on the server. Audit all installed marketplace apps against their permission requirements and ensure macro execution is restricted to trusted users.
Confluence and Jira are routinely deployed together and connected via application links. The application link configuration stores service account credentials and OAuth tokens used for bi-directional integration — issue embedding in pages, Jira gadgets in Confluence dashboards, and unified user directories. These integration credentials are stored in the Confluence database and accessible to Confluence administrators via the admin panel, but are also sometimes exposed in backup files, exported XML dumps, or via the admin REST API on instances with lax access controls.
# Check application links configuration (requires admin)
curl -s -u "admin:password" \
"${CONFLUENCE_URL}/rest/applinks/1.0/applicationlink" \
| python3 -m json.tool | grep -E '"name"|"displayUrl"|"typeId"'
# Application link OAuth credentials endpoint
curl -s -u "admin:password" \
"${CONFLUENCE_URL}/rest/applinks/1.0/applicationlink/{id}/credentials" \
| python3 -m json.tool
# Check for Jira macros in pages that may embed sensitive project data
curl -s -H "Authorization: Bearer ${TOKEN}" \
"${CONFLUENCE_URL}/rest/api/content/search?cql=type%3Dpage+AND+text+%7E+%22jira%22&limit=10" \
| python3 -m json.tool | grep '"title"'
# Database-level exposure: confluence.cfg.xml contains DB credentials
# Check for backup files accessible via web root
for path in \
"/confluence.cfg.xml" \
"/WEB-INF/confluence.cfg.xml" \
"/confluence/WEB-INF/classes/confluence.cfg.xml" \
"/backup/confluence-backup.zip"; do
CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"${CONFLUENCE_URL}${path}")
echo "${CODE} ${path}"
done
Confluence XML backup exports (created via Administration > Backup & Restore) contain all page content, user data, and space configurations in plaintext XML. These backups are stored by default in <confluence-home>/backups/ and are sometimes inadvertently placed in web-accessible directories or uploaded to shared storage. A single XML backup provides complete data exfiltration without any active exploitation.
Confluence Data Center deployments use a multi-node clustering architecture where nodes communicate over dedicated cluster ports — typically port 5801 (Hazelcast) for cache synchronization and distributed state. These inter-node communication ports must never be exposed to untrusted networks, as they implement minimal authentication and can allow cluster manipulation or data extraction from a network-adjacent position. Additionally, shared home storage (NFS/SAN) used by Data Center clusters must be properly access-controlled to prevent node-level credential theft.
# Scan for exposed Confluence Data Center cluster ports
# Hazelcast default port: 5801
nmap -sV -p 5801,5701,8090,8091 confluence.example.com
# Check if Hazelcast management center is exposed
curl -s -o /dev/null -w "%{http_code}" \
"http://confluence.example.com:5801/"
# Test for exposed synchrony (collaborative editing) endpoint
# Synchrony runs on port 8091 by default in Data Center
curl -s -o /dev/null -w "%{http_code}" \
"http://confluence.example.com:8091/synchrony"
# Check Confluence admin clustering status (requires admin auth)
curl -s -u "admin:password" \
"${CONFLUENCE_URL}/rest/api/cluster/nodes" \
| python3 -m json.tool
# Verify load balancer health check endpoints (sometimes unauthenticated)
for path in "/status" "/rest/api/2/serverInfo" "/rest/api/space?limit=0"; do
CODE=$(curl -s -o /dev/null -w "%{http_code}" \
"${CONFLUENCE_URL}${path}")
echo "${CODE} ${path}"
done
# Check if admin pages bypass load balancer auth (direct node access)
curl -s -o /dev/null -w "%{http_code}" \
"http://node1.internal.example.com:8090/admin/systeminfo.action"
Data Center environments also introduce the risk of session fixation across nodes if session storage is improperly configured. Shared PostgreSQL or distributed session stores must enforce TLS for intra-cluster communication and use properly scoped connection credentials that cannot be extracted from one node to access another.
| Area | Check | Priority |
|---|---|---|
| Patch Management | Upgrade to latest Confluence version; verify CVE-2023-22527 and CVE-2022-26134 are patched | Critical |
| Anonymous Access | Disable global anonymous access unless explicitly required; audit per-space permissions | Critical |
| API Tokens | Audit active Personal Access Tokens; enforce token expiration; revoke unused tokens | High |
| Setup Wizard | Verify setup endpoints return 302; disable access after initial configuration | High |
| HTML Macro | Keep HTML macro disabled; restrict script macros to administrators only | High |
| User Enumeration | Disable or restrict /rest/api/user/search for anonymous and low-privilege users |
Medium |
| Plugin Audit | Remove unused marketplace apps; pin approved plugin versions; review ScriptRunner permissions | High |
| Backup Security | Store XML backups outside web root; encrypt at rest; restrict access to backup directory | High |
| Jira Integration | Use dedicated service accounts with minimal permissions for application links; rotate credentials annually | Medium |
| Data Center Ports | Block Hazelcast (5801) and Synchrony (8091) ports at firewall; restrict to cluster subnet only | Critical |
| Database Access | Restrict Confluence DB user to minimum required permissions; use TLS for DB connections | High |
| Admin Console | Enable WebSudo (admin session re-authentication); restrict admin IP access at reverse proxy level | High |
Confluence security assessments should be integrated into your regular penetration testing cycle — at minimum annually and after any major version upgrade. Given that both recent critical CVEs targeted the template and macro processing layer, treat any new Confluence feature announcement as a prompt to review the associated attack surface before deployment.
The combination of rich internal content, deep Jira integration, long-lived API tokens, and complex permission inheritance makes Confluence one of the most rewarding targets for an attacker who gains initial access to an enterprise network. Defense-in-depth — patching, access control, token lifecycle management, and egress monitoring — is the only viable strategy.
Ironimo's security scanning platform tests Confluence instances for CVE exposure, misconfigured space permissions, API token misuse, and anonymous access — with actionable remediation guidance for every finding.
Start free scan