Hunt Atlassian CVE-2026-21589: two dots in your access log


On 2 October 2026, three days before any advisory, Atlassian attached a 511 byte file named rewrite.config to public tickets for Jira, Jira Service Management, Confluence, and Crowd. It was a block rule. On 5 October the advisory followed: CVE-2026-21589, an arbitrary file access flaw that lets an unauthenticated caller read a specific file from the web application root of eight self-hosted Atlassian Data Center products: Bitbucket, Confluence, Jira Software, Jira Service Management, Bamboo, Crowd, Crucible, and Fisheye.
Atlassian handed defenders the detection on day one: the exact WAF regex, guidance to URL-decode each access-log line up to twice, and three blocking rules. So this post teaches what a hit looks like before you patch, what a block looks like after you mitigate, and which nodes never got the block.
Exploitation attempts have started. The Hacker News reported on 7 October that Previdian's honeypots logged 15 exploitation attempts from three IPs, beginning two hours after watchTowr published technical details, and that a public Nuclei scanning template is out. Those are attempts against honeypots, with no confirmed compromises reported. Atlassian found no evidence of exploitation in its patched Cloud products and cannot confirm whether self-hosted instances were affected. CVE-2026-21589 is not on CISA KEV as of catalog 2026.10.04, pulled again on 6 October. The precedent is CVE-2021-26086, a Jira path traversal file read CISA added to KEV on 12 November 2024.
Carry two questions. Which of your Atlassian nodes, mirrors included, can an outsider reach without logging in? And if a two-dot request came back 200 last week, would any log tell you?
How the attack works
Two dots beside a separator
The CVE record calls this a path traversal, the CWE-22 class. Per Atlassian's regex, the request puts .. immediately next to /, \, or ::, raw or URL-encoded, including repeat-encoded %25 forms, and a ; or end of URL may close it. That escapes the intended path and returns a file from the web application root directory.
A known path, not a listing
The request needs no login. But the attacker must already know the target file's exact name and path, because the flaw cannot list a directory. Atlassian says "in some configurations, there may be sensitive files present that increase your risk," and names no files. Neither do we.
Our reading: default install layouts are public, so the exact-path requirement is a weak brake.
Risk: what the Atlassian stack holds
Bitbucket holds source code. Bamboo, Crucible, and Fisheye sit in the build and review path. Confluence holds internal documentation. Jira and Jira Service Management hold tickets and change records. Crowd holds directory and single sign-on settings. Every version before the fix is affected.
Atlassian rates it Critical, 9.3 under CVSS 4.0, by its own assessment. No exposure count is published.
Our reading: after a confirmed 200 on an unpatched node, rotate what its web root could expose, as precaution rather than proof.
Mitigate and reduce riskrict internet-facing instances, "including those with user authentication," from external access until you act.
Option 1, a WAF or proxy rule using Atlassian's regex, covers all eight products.
Option 2, Tomcat's RewriteValve plus rewrite.config on every node, covers Confluence, Jira, Jira Service Managem
Patch status today
Atlassian's advisory lists these fixed versions. Patch to one of them or later.
Bitbucket Data Center: 9.4.26, 10.2.8, 10.5.1
Confluence Data Center: 9.2.26, 10.2.19
Jira Software Data Center: 9.12.40, 10.3.26, 11.3.12
Jira Service Management Data Center: 5.12.40, 10.3.26, 11.3.12
Bamboo Data Center: 10.2.24, 12.1.12
Crowd Data Center: 6.3.7, 7.0.3, 7.1.7, 7.2.4
Crucible: 4.9.15
Fisheye: 4.9.15
The Hacker News notes the CVE record lists Crowd 7.1.1 and Bamboo 10.2.4 instead. Follow the advisory. As of this stamp on 6 October, the Jira Service Management ticket still marks 5.12.40 unreleased (10.3.26 and 11.3.12 are marked released on the ticket), so confirm your build is downloadable first.
Interim options
If you cannot patch, Atlassian says to restent, Bamboo, and Crowd. The rule ends in [F,L], and Tomcat documents [F] as an immediate 403.
Option 3, a top rule in Bitbucket's app/WEB-INF/urlrewrite.xml on every node, mirror, and mirror farm node, returns 404 via /mvc/error404.
Crucible and Fisheye have Option 1 only. Atlassian calls these mitigations "limited and not a replacement for patching." Each leaves a signature: 403 from the RewriteValve, 404 to /mvc/error404 from Bitbucket, and whatever your WAF returns.
How to hunt the activity
For threat hunting, Atlassian gives two paths: decode each request line up to twice and look for .. beside /, \, or ::, or run the published regex over raw lines. Here it is verbatim from the advisory:
(?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*Our reading of status, which Atlassian does not spell out: a 200 on a match before you patched or blocked is the one to chase, and 403 or 404 to /mvc/error404 means the block fired. Query text and field names around the regex are ours, so every hunt is test first. The table under the hunts, "Interpret before you escalate", says what is benign and what is not.
Hunt in Splunk: raw regex plus double decode, split by status (test first)
index=YOUR_ATLASSIAN_HTTP_INDEX host IN (YOUR_ATLASSIAN_NODES)
| eval path=coalesce(uri, url, uri_path, http_uri)
| eval client=coalesce(src_ip, src, clientip, client_ip)
| eval status=tonumber(coalesce(status, http_status, status_code))
| eval raw_hit=if(match(_raw, "(?is).*(?:/|\\\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*"), 1, 0)
| eval decoded=urldecode(urldecode(path))
| eval decoded_hit=if(match(decoded, "(/|\\\\|::)\.\.|\.\.(/|\\\\|::)"), 1, 0)
| where raw_hit=1 OR decoded_hit=1
| stats count as hits, min(_time) as first_seen, max(_time) as last_seen, values(path) as paths by client, host, status
| convert ctime(first_seen) ctime(last_seen)
| sort 0 client first_seenField mapping: raw_hit is Atlassian's pattern with each \\ doubled, because Splunk string literals consume one backslash level. The decode check is our version of the two-pass guidance. Splitting by host shows which node still answers 200. Test first.
False positives: your own scanners, and matches in a referrer or user agent rather than the request.
Empty result: confirm proxy, WAF, or Tomcat access logs reach this index with the encoded URL intact, and retention covers early October.
Hunt in Kibana: same pattern on url.original, first seen per source (test first)
FROM YOUR_PROXY_OR_WAF_INDEX
| WHERE url.domain IN ("YOUR_ATLASSIAN_HOST")
| WHERE url.original RLIKE """.*(/|\\|::|%(25)*(2[fF]|5[cC])|(:|%(25)*3[aA]){2})(\.|%(25)*2[eE]){2}((/|\\|::|%(25)*(2[fF]|5[cC])|(:|%(25)*3[aA]){2}|;|%(25)*3[bB]).*)?"""
| STATS hits = COUNT(*), first_seen = MIN(@timestamp), last_seen = MAX(@timestamp) BY source.ip, http.response.status_code
| SORT first_seen ASCField mapping: this ES|QL runs in Discover. Lucene regex lacks inline flags and non-capturing groups, so this is our translation of Atlassian's pattern. Swap in your ECS fields. Test first against lines the Splunk or KQL hunt matched.
False positives: the same scanners, plus shared egress addresses.
Empty result: confirm url.original keeps the encoded URL.
Hunt in Falcon CQL: which Atlassian nodes never got the block (test first)
#event_simpleName=ProcessRollup2
| FileName=/^(java|tomcat\d*)(\.exe)?$/i
| CommandLine=/(confluence|atlassian-jira|bitbucket|bamboo|crowd|fisheye|crucible)/i
| groupBy([aid, ComputerName], function=[max(@timestamp, as=last_atlassian_process)])
| join(query={
TargetFileName=/(rewrite\.config|server\.xml|urlrewrite\.xml|crowd\.xml)$/i
| groupBy([aid], function=[max(@timestamp, as=last_config_write), collect([TargetFileName])])
}, field=aid, include=[last_config_write, TargetFileName], mode=left)
| case {
last_config_write=* | coverage := "config write seen" ;
* | coverage := "no config write seen" ;
}
| table([ComputerName, last_atlassian_process, last_config_write, TargetFileName, coverage], limit=1000)Field mapping: start the time picker at 2 October 2026. This lists hosts running Atlassian Java or Tomcat and whether rewrite.config, server.xml, urlrewrite.xml, or Crowd's crowd.xml changed since. It cannot see the read itself. Field names are ours. Test first.
False positives: routine upgrades touch the same files.
Empty result: confirm Falcon covers each node and records writes to plain config files. A WAF-only block will not show here.
Hunt in KQL: WAF or proxy URLs, then a follow-on session (test first)
let Window = ago(30d);
let AtlassianHosts = dynamic(["YOUR_ATLASSIAN_HOST"]);
let Traversal = @"(?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*";
CommonSecurityLog
| where TimeGenerated >= Window
| where DestinationHostName in~ (AtlassianHosts)
| where RequestURL matches regex Traversal
| project HitTime = TimeGenerated, SourceIP, DestinationHostName, RequestURL, DeviceAction
| join kind=leftouter (
SigninLogs
| where TimeGenerated >= Window
| where ResultType == "0"
| project LoginTime = TimeGenerated, SourceIP = IPAddress, UserPrincipalName, AppDisplayName
) on SourceIP
| where isnull(LoginTime) or LoginTime between (HitTime .. (HitTime + 1h))
| order by HitTime ascField mapping: for Microsoft Sentinel, Traversal is Atlassian's regex verbatim in a KQL verbatim string. The join to a sign-in from the same source within an hour is our reading, not a published indicator. Map your connector's status field before filtering on it. Test first.
False positives: NAT pairs a probe with an unrelated login.
Empty result: confirm WAF or proxy events land in CommonSecurityLog with the full URL.
Interpret before you escalate
Finding | Benign read | Escalate when |
Regex match with status 200 | A scanner you run, or a node already patched | Unauthenticated source against an unpatched node; with attempts reported and a public Nuclei template out (THN, Previdian), treat it as live |
Match with 403, or 404 to /mvc/error404 | Your interim block fired | A sibling node answers 200 to the same source |
Atlassian node with no config write since 2 October | Patched instead of mitigated | Still unpatched and reachable, so no coverage |
Match, then a sign-in from the same source | Shared NAT | Unfamiliar source, unfamiliar account, short gap |
Empty results | Nothing matched | Logs, raw URLs, sensors, or retention are missing, so fix coverage first |
Sources
Atlassian advisory, CVE-2026-21589 Arbitrary File Access Vulnerability impacts Multiple Products, 5 October 2026: https://confluence.atlassian.com/security/cve-2026-21589-arbitrary-file-access-vulnerability-impacts-multiple-products-1870495748.html
Atlassian tickets: https://jira.atlassian.com/browse/BSERV-20604, https://jira.atlassian.com/browse/CONFSERVER-104488, https://jira.atlassian.com/browse/JSDSERVER-16809, https://jira.atlassian.com/browse/JRASERVER-79546, https://jira.atlassian.com/browse/BAM-26567, https://jira.atlassian.com/browse/CWD-6610, https://jira.atlassian.com/browse/CRUC-8741, https://jira.atlassian.com/browse/FE-7583
CVE record, CVE-2026-21589: https://www.cve.org/CVERecord?id=CVE-2026-21589
The Hacker News, Critical Atlassian Flaw Lets Unauthenticated Attackers Read Known Files Across 8 Products, 6 October 2026: https://thehackernews.com/2026/10/critical-atlassian-flaw-lets.html
watchTowr Rapid Reaction, CVE-2026-21589, 6 October 2026: https://watchtowr.com/intelligence/atlassian-jira-confluence-arbitrary-file-read-cve-2026-21589/
Help Net Security, 6 October 2026: https://www.helpnetsecurity.com/2026/10/06/atlassian-data-center-cve-2026-21589/
Apache Tomcat, The Rewrite Valve: https://tomcat.apache.org/tomcat-9.0-doc/rewrite.html
NVD, CVE-2021-26086: https://nvd.nist.gov/vuln/detail/CVE-2021-26086
CISA Known Exploited Vulnerabilities Catalog (CVE-2026-21589 absent as of catalog 2026.10.04): https://www.cisa.gov/known-exploited-vulnerabilities-catalog
The Hacker News, "Atlassian Data Center Flaw Draws Exploitation Attempts Within Two Hours of Public Details" (citing Previdian), 7 October 2026: https://thehackernews.com/2026/10/atlassian-data-center-flaw-draws.html
What This Means for Your Team
List every Atlassian node you run, mirrors included, with version and exposure. Patch to the advisory's fixed builds. Where you cannot yet, restrict the instance or apply the interim block that fits the product. Then run the four hunts. A 200 on an unpatched node is the one to chase, a 403 or 404 means your block held, and a node with no config write and no patch has no coverage.
Inception Protection
Inception Protection is our managed detection and response service, and it works with the Microsoft licenses you already have. Atlassian nodes only help us if their proxy, identity, and endpoint signals reach us, so we start there. Then we read those signals as one story, and you keep the decisions.
Inception Foresight
If you want to see how well your Microsoft environment would surface activity like this, the free Inception Foresight M365 Assessment is a good place to start: https://www.inceptionsecurity.com/m365assessment. You can also follow Inception Security on LinkedIn and @inceptionsec on X.



