1. 개요
Atlassian은 2026년 10월 5일, 여러 Data Center 제품에 영향을 주는 임의 파일 접근(Arbitrary File Access) 취약점 CVE-2026-21589를 공개했습니다. 인증받지 않은 공격자가 웹 애플리케이션 루트 디렉터리 안의 특정 파일에 접근할 수 있는 취약점이며, 심각도는 Critical(CVSS 4.0 기준 9.3)입니다. 공격하려면 대상 파일의 정확한 이름과 경로를 알아야 하고, 디렉터리 목록을 볼 수는 없습니다. 그러나 설정에 따라 민감한 파일이 있으면 위험이 커집니다.
영향받는 제품은 Bitbucket, Confluence, Jira Software, Jira Service Management, Bamboo, Crowd Data Center와 Crucible, Fisheye이며, 모든 버전이 해당됩니다. Atlassian Cloud 제품은 이미 패치되어 있어 고객이 할 일은 없습니다.
2. 대응 우선순위
근본적인 해결책은 수정 버전으로 업그레이드하는 것입니다(8장 참고). 바로 업그레이드할 수 없다면 다음 순서로 대응해 주십시오.
먼저, 인터넷에 노출된 인스턴스는 조치를 마칠 때까지 외부 접근을 차단하는 것이 좋습니다. 다음으로, 3장의 임시조치 중 환경에 맞는 방법 하나를 적용합니다. 마지막으로 7장에 따라 과거 액세스 로그에 공격 시도가 있었는지 점검하고, 업그레이드 일정을 잡습니다.
3. 임시조치 방법 선택
Atlassian은 세 가지 임시조치를 제시합니다. 세 방법 모두 같은 정규식으로 같은 경로 탐색 패턴을 차단하며, 차이는 차단하는 위치뿐입니다. 따라서 제품별로 아래 방법 중 하나만 적용하면 됩니다. 두 가지를 함께 적용하면 다중 방어가 되지만 필수는 아닙니다.
| 제품 | 적용 가능한 방법 |
|---|---|
| Confluence, Jira Software, Jira Service Management, Bamboo, Crowd | 방법 1(WAF/프록시) 또는 방법 2(Tomcat RewriteValve) |
| Bitbucket (미러, 미러 팜 포함) | 방법 1(WAF/프록시) 또는 방법 3(urlrewrite.xml) |
| Crucible, Fisheye | 방법 1(WAF/프록시)만 가능 |
방법 1은 앞단 프록시나 WAF에서 처리합니다. 애플리케이션을 재시작할 필요가 없고 여러 제품에 한 번에 적용할 수 있습니다. 다만 모든 사용자 트래픽이 반드시 그 프록시를 거쳐야 효과가 있습니다. 방법 2와 3은 애플리케이션 서버에서 처리하므로 우회 경로 걱정이 없습니다. 대신 노드를 재시작해야 하고 모든 노드에 적용해야 합니다.
4. 방법 1: 리버스 프록시 / WAF에서 차단
4.1 차단 규칙
Atlassian 권고문의 원본 정규식은 다음과 같습니다.
(?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*
이 규칙은 ..가 /, \, :: 바로 옆에 붙은 패턴을 차단합니다. URL 인코딩(%2e, %2f, %5c, %3a, %3b)과 다중 인코딩(%252e 등)도 함께 막습니다. AWS WAF, Cloudflare 같은 상용 WAF를 쓰고 있다면 이 정규식을 대소문자 무시 옵션과 함께 URI 경로 조건에 등록하면 됩니다.
nginx와 Apache에서는 설정 파일의 이스케이프 처리 방식 때문에, 아래처럼 표기만 바꾼 정규식을 사용합니다. 차단 대상은 원본과 같습니다. 역슬래시 \\는 \x5c로, \.는 [.]로 바꿨고, 앞뒤의 .*는 빼고 대소문자 무시는 각 웹서버의 플래그로 처리했습니다.
(?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:[.]|%(?:25)*2e){2}(?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$)
중요한 점이 있습니다. nginx와 Apache는 요청 경로의 /../를 스스로 정리하고 인코딩도 풀어서 처리합니다. 그래서 정리된 경로만 검사하면 우회될 수 있으므로, 클라이언트가 보낸 원본 요청 URI를 반드시 검사해야 합니다.
4.2 nginx 적용 절차
1단계: Nginx 디렉토리 또는 conf 설정 파일 백업
2단계: 공통 snippet 파일 생성. 이 파일은 nginx.conf가 http 블록에 자동으로 include하는 경로(conf.d/ 등) 밖에 만들어야 합니다. 그 경로 안에 두면 if가 http 레벨에서 로드되어 문법 오류가 납니다.
mkdir -p /etc/nginx/snippets
cat > /etc/nginx/snippets/cve-2026-21589.conf <<'EOF'
# CVE-2026-21589 임시조치 (Atlassian path traversal 차단)
if ($request_uri ~* "(?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:[.]|%(?:25)*2e){2}(?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$)") {
return 403;
}
EOF
restorecon -Rv /etc/nginx/snippets 2>/dev/null
heredoc 구분자를 'EOF'처럼 따옴표로 감싸야 쉘이 $request_uri를 변수로 해석하지 않고 그대로 저장합니다.
3단계: Atlassian 서비스의 server 블록에 include 추가. Atlassian 제품을 프록시하는 각 conf 파일에서 모든 server { 블록(80, 443) 바로 아래에 다음 한 줄을 넣습니다. location 블록 안에 넣으면 안 됩니다.
server {
include /etc/nginx/snippets/cve-2026-21589.conf;
listen 443 ssl;
server_name jira.example.com;
...
}
이 규칙은 Atlassian 취약점용이므로 Atlassian 제품에만 적용하는 것을 권장합니다. GitLab이나 Artifactory처럼 인코딩된 경로를 정상적으로 쓰는 서비스에 넣으면 정상 요청이 막힐 수 있습니다.
4단계: 문법 검사 후 반영.
nginx -t && systemctl reload nginx
4.3 Apache httpd 적용 절차
mod_rewrite가 켜져 있어야 합니다. Debian/Ubuntu는 a2enmod rewrite를 실행하고, RHEL 계열은 보통 기본으로 켜져 있습니다. mod_rewrite 규칙은 VirtualHost끼리 상속되지 않으므로, Atlassian 서비스를 프록시하는 모든 VirtualHost(80, 443)에 각각 적용해야 합니다. 공통 파일은 자동 로드 경로(conf.d/) 밖에 만들고 각 VirtualHost에서 Include합니다.
mkdir -p /etc/httpd/snippets # Debian/Ubuntu는 /etc/apache2/snippets
cat > /etc/httpd/snippets/cve-2026-21589.conf <<'EOF'
# CVE-2026-21589 임시조치
RewriteEngine On
RewriteCond %{REQUEST_URI} (?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:[.]|%(?:25)*2e){2}(?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$) [NC,OR]
RewriteCond %{THE_REQUEST} (?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:[.]|%(?:25)*2e){2}(?:/|\x5c|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|\s|$) [NC]
RewriteRule ^ - [F,L]
EOF
%{THE_REQUEST}는 GET /경로 HTTP/1.1처럼 요청 줄 전체를 담고 있습니다. 그래서 경로 끝을 판단하는 조건에 공백(\s)을 추가했습니다.
각 VirtualHost에는 다음 한 줄을 넣습니다.
<VirtualHost *:443>
ServerName confluence.example.com
Include /etc/httpd/snippets/cve-2026-21589.conf
...
ProxyPass / http://127.0.0.1:8090/
ProxyPassReverse / http://127.0.0.1:8090/
</VirtualHost>
mod_rewrite는 ProxyPass보다 먼저 처리되므로, 403으로 막힌 요청은 백엔드까지 가지 않습니다. 반영은 apachectl configtest && systemctl reload httpd로 합니다. Debian/Ubuntu에서는 서비스 이름이 apache2입니다.
4.4 방법 1 적용 시 주의사항
방법 1은 모든 트래픽이 프록시를 거칠 때만 효과가 있습니다. 각 Atlassian 서버의 Tomcat 포트(Jira 8080, Confluence 8090, Bitbucket 7990, Bamboo 8085, Crowd 8095, Fisheye/Crucible 8060 등)로 바로 접속할 수 있다면, 방화벽에서 해당 포트를 프록시 서버 IP에만 열어두십시오. 그렇게 할 수 없다면 방법 2나 3을 함께 적용하십시오.
5. 방법 2: Tomcat RewriteValve (Confluence, Jira, JSM, Bamboo, Crowd)
작업 전에 인스턴스를 백업하십시오. 클러스터라면 아래 절차를 모든 노드에서 진행해야 합니다.
1단계: 노드를 종료합니다.
2단계: RewriteValve를 활성화합니다. 아래 표에서 제품별 설정 파일을 찾아 백업 사본을 만듭니다.
| 제품 | 설정 파일 |
|---|---|
| Confluence, Jira, JSM, Bamboo | <설치경로>/conf/server.xml |
| Crowd | apache-tomcat/conf/Catalina/localhost/crowd.xml 또는 apache-tomcat/conf/server.xml 중 애플리케이션 <Context>가 있는 파일 |
애플리케이션을 나타내는 <Context> 요소(docBase에 제품 경로가 있는 요소)를 찾습니다. 그 안에 아래 줄이 없으면 추가합니다.
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
3단계: rewrite.config를 설치합니다. 아래 표의 WEB-INF 디렉터리에 rewrite.config를 만듭니다. 파일이 이미 있으면 백업한 뒤 기존 내용 뒤에 덧붙입니다.
제품 | WEB-INF 위치 |
|---|---|
Confluence |
|
Jira, JSM |
|
Bamboo |
|
Crowd |
|
# Primary check: Tomcat's decoded, normalized request path (no query string). RewriteCond %{REQUEST_PATH} (?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).* RewriteRule (?s)^.*$ /?denied [F,L]
# Raw-URI fallback RewriteCond %{REQUEST_URI} (?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).* RewriteRule (?s)^.*$ /?denied [F,L]
4단계: 노드를 시작합니다.
WEB-INF 아래 파일은 업그레이드하거나 재설치하면 사라질 수 있습니다. 수정 버전으로 업그레이드하기 전에 설치 디렉터리를 새로 만드는 작업을 했다면, 다시 적용되어 있는지 확인하십시오.
6. 방법 3: urlrewrite.xml (Bitbucket 전용)
작업 전에 인스턴스를 백업하십시오. 클러스터의 모든 노드뿐 아니라 모든 Bitbucket 미러와 미러 팜 노드에도 적용해야 합니다.
<설치경로>/app/WEB-INF/urlrewrite.xml 파일을 열고, 아래 <rule>을 기존의 모든 <rule>보다 앞에 넣은 뒤 Bitbucket을 재시작합니다.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN" "dtds/urlrewrite4.0.dtd">
<urlrewrite decode-using="utf8">
<rule>
<from>(?is).*(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2})(?:\.|%(?:25)*2e){2}(?:/|\\|::|%(?:25)*(?:2f|5c)|(?::|%(?:25)*3a){2}|;|%(?:25)*3b|$).*</from>
<set type="status">404</set>
<to>/mvc/error404</to>
</rule>
<rule>
[...기존 규칙...]