flawopen.com/Teardowns/cve-2026-21589-atlassian-arbitrary-file-access
CVE-2026-21589:Atlassian Data Centerのファイルアクセス
Atlassian のアドバイザリと10月12日の MS-ISAC 報告はリスクと緊急性を示しますが、特定顧客のインスタンスでの悪用を証明するものではありません。[1], [4], [5], [10]
来館者が指定した棚の場所を受け付ける図書館を想像してください。すべての棚を見て回ることはできませんが、特定の本の場所を知っていれば、境界確認の不備によって職員が閲覧エリア外から本を持ってくることがあります。修正では、解決されたパスを許可範囲内に保ち、製品ごとの更新を適用します。[1], [4]
主要な概念と専門用語
任意ファイルアクセス- 想定された範囲外のファイルにリクエストからアクセスできる状態です。Atlassianが説明するのはWebアプリのルート内にある特定ファイルであり、ファイルシステム全体ではありません。[1], [4]
Data Center- Atlassian製品のセルフマネージド展開モデルです。アドバイザリは8製品を対象とし、AtlassianはCloud製品は修正済みとしています。[1]
既知パスの前提- 対象ファイルの正確な名前とパスを事前に知る必要があります。アドバイザリによると、ディレクトリの列挙はできません。[1]
CVSS 4.0- Atlassianは独自評価で本脆弱性をCritical、CVSS 4.0で9.3としています。[1]
Router.unescapeSlashes()- 共有ライブラリはリソース処理前にエンコードされた区切り
::を/へ戻します。watchTowrのソース分析ではこのデコード境界が重要です。[1], [4] CWE-22- パストラバーサルの弱点に対するFlawOpenの編集上の分類です。パスが意図したディレクトリ内に十分制限されていません。AtlassianのアドバイザリはCWEを指定していません。[6]
フレームワーク対応
- FlawOpenによるMITRE CWEへの概念上の対応付けです。ベンダーやCVEレコードがこの研究デモに弱点IDを割り当てたものではありません。 CWE-22
根本原因の分析 (Root Cause)
watchTowrによる共有ライブラリatlassian-plugins-webresourceの分析は、パスデコード境界を示しています。Router.unescapeSlashes()は::を/へ変換し、リソースルートはリクエスト制御可能なパス要素にこの関数を適用してからリソース処理を呼び出します。後段の検索はリソース名を分割し、残りの相対パスをcreateResourceWithRelativePath()へ渡します。代替の区切り表現により、トラバーサル検査の前提を回避できます。研究者はJira、Confluence、BitbucketでTomcatアプリケーションコンテキスト内のファイル読み取りを実証し、Atlassianは8製品を影響対象としています。報告によると、検証したパスはTomcatコンテキスト外へは出ませんでした。条件がそろうと、読み取り可能なWEB-INF/classes/crowd.propertiesからCrowdアプリケーションパスワードが平文で露出する可能性があります。影響は設定とCrowdへの到達性に依存します。BleepingComputerは、技術報告とPoC公開から数時間後にPrevidianセンサーが試行を観測したと報じています。これはハニーポットへの試行であり、顧客システムでの成功を示すものではありません。以下の脆弱なJava断片はwatchTowrの報告に基づきます。安全側は一般的な境界検証例で、未公開のAtlassian修正コードではありません。各製品の公式修正版を適用してください。[1], [4], [5]
ステップ・バイ・ステップの攻撃フロー
リソース検索にデコード済みパスが渡る
ヘルパーがパス要素を分割し、残りの相対パスをリソースファクトリーへ渡します。代替区切りによりトラバーサル検査の想定を回避できます。[4]
観測された試行は緊急度を高めるが侵害の証明ではない
10月12日、Center for Internet Security の MS-ISAC アドバイザリは、CVE-2026-21589 が実環境で悪用されたとの報告があると伝えました。被害者を特定せず、インシデントの証拠資料も公開していないため、MS-ISACによる悪用報告として扱い、特定顧客へのアクセス確認とは区別してください。10月5日の Atlassian アドバイザリでは、同社の調査で Cloud 製品の悪用証拠は見つかっておらず、Cloud 製品には修正が適用済みとされていました。この調査結果は Cloud を対象としており、脆弱性の悪用報告を伝えた MS-ISAC の発表とは矛盾しません。いずれの声明も、特定のインスタンスで何が起きたかを確定するものではありません。[1], [10]
ソースコード比較:脆弱 vs 堅牢化
脆弱なコード断片は、watchTowr が公開した対象 web-resource ライブラリのソースコード上のパス変換を示すもので、攻撃リクエストではありません。下段は Java の一般的な防御例であり、Atlassian のパッチではありません。信頼できるルートから SecureDirectoryStream のハンドルで順にたどり、各要素のシンボリックリンクを拒否し、読み取りバイト数を制限します。呼び出し側は一度だけデコードした相対パスと、信頼できるディレクトリをルートとして開いた SecureDirectoryStream を渡す必要があります。SecureDirectoryStream に対応しないファイルシステムプロバイダーもあるため、その場合は安全側に失敗させてください。製品ごとのベンダー修正版を適用してください。この例は、信頼できるリソースツリーを前提とします。ディレクトリやファイルを信頼できない主体が変更できず、通常ファイルだけを含む必要があります。コード自体はファイル種別を検証しません。バイト上限と、進行しない読み取りへの回数制限は読み取りを制限しますが、汎用的なファイル配信処理ではありません。呼び出し側は一度だけデコードした相対パスを渡し、信頼できるルートストリームを開いたまま保持する必要があります。ファイルシステムプロバイダーは SecureDirectoryStream をサポートしない場合があるため、利用できなければ安全側に失敗してください。[4], [7]
public static String unescapeSlashes(String string) {
return string.replaceAll("::", "/");
}
static byte[] readUnder(SecureDirectoryStream<Path> root, Path relative, int maxBytes) throws IOException {
if (relative.isAbsolute() || relative.getNameCount() == 0 || maxBytes < 0) {
throw new SecurityException("Expected a relative path and non-negative limit");
}
List<SecureDirectoryStream<Path>> opened = new ArrayList<>();
SecureDirectoryStream<Path> parent = root;
try {
for (int i = 0; i < relative.getNameCount() - 1; i++) {
Path part = relative.getName(i);
if (part.toString().isEmpty() || part.toString().equals(".") || part.toString().equals("..")) {
throw new SecurityException("Invalid path component");
}
parent = parent.newDirectoryStream(part, LinkOption.NOFOLLOW_LINKS);
opened.add(parent);
}
Path leaf = relative.getFileName();
if (leaf.toString().isEmpty() || leaf.toString().equals(".") || leaf.toString().equals("..")) {
throw new SecurityException("Invalid file name");
}
try (SeekableByteChannel channel = parent.newByteChannel(
leaf, Set.of(StandardOpenOption.READ, LinkOption.NOFOLLOW_LINKS))) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteBuffer buffer = ByteBuffer.allocate(8192);
int total = 0;
int zeroReads = 0;
while (true) {
int count = channel.read(buffer);
if (count == -1) break;
if (count == 0) {
if (++zeroReads >= 3) throw new IOException("Resource read made no progress");
continue;
}
zeroReads = 0;
if (count > maxBytes - total) throw new IOException("Resource exceeds size limit");
out.write(buffer.array(), 0, count);
total += count;
buffer.clear();
}
return out.toByteArray();
}
} finally {
for (int i = opened.size() - 1; i >= 0; i--) opened.get(i).close();
}
}
エンジニアリング&システム堅牢化チェックリスト
- ✓修正済みの最低バージョン:Bitbucket 9.4.26 / 10.2.8 / 10.5.1、Confluence 9.2.26 / 10.2.19、Jira Service Management 5.12.40 / 10.3.26 / 11.3.12、Jira Software 9.12.40 / 10.3.26 / 11.3.12、Bamboo 10.2.24 / 12.1.12、Crowd 6.3.7 / 7.0.3 / 7.1.7 / 7.2.4、CrucibleとFisheye 4.9.15。製品ごとの系列を確認してください。[1]
- ✓影響を受ける8つのセルフマネージド製品(Data Centerと明記された6製品、およびCrucibleとFisheye)、各ノードとミラー、インターネット公開インスタンスを棚卸しします。AtlassianはCloud製品を修正済みとしています。[1]
- ✓各製品をアドバイザリ記載の修正版へ更新し、クラスタの全ノードで実行中のバージョンを確認します。[1]
- ✓すぐにパッチを適用できない場合は、修正または緩和策を適用するまで外部アクセスを制限してください。製品に適した一時的なWAF/プロキシ、Tomcat RewriteValve、またはBitbucketのurlrewrite.xmlルールを関連する全ノードに適用し、依存する前にエンコード形式をテストしてください。[1]
- ✓Atlassianの指示どおりアクセスログのURLを最大2回デコードし、
/、\、::に隣接する..を調べます。生ログも保管してください。[1], [9] - ✓一致するリクエストは調査の手掛かりであり、ファイルが返された証拠ではありません。Atlassianは侵害の有無を確認できないため、存在した機密ファイルを評価し、得られた証拠に基づいて対応を判断してください。[1], [9]
- ✓独自のファイル処理では、正規化層を一つに定め、許可ルート内への包含を強制し、シンボリックリンク、競合状態、各デコード層を考慮します。[7], [6]
参考資料
- Atlassianセキュリティアドバイザリ — CVE-2026-21589
- CERT-EU — Atlassian複数製品の重大な脆弱性
- カナダ・サイバーセキュリティセンター — Atlassian勧告AV26-1002
- watchTowr Labs — CVE-2026-21589 technical analysis
- BleepingComputer — observed CVE-2026-21589 exploitation attempts
- MITRE CWE-22 — Path Traversal (FlawOpen editorial mapping)
- Oracle Java API — SecureDirectoryStream
- Previdian — sensor telemetry and exploitation methodology
- NIST SP 800-61 Rev. 3 — インシデント対応の推奨事項
- Center for Internet Security MS-ISAC — CVE-2026-21589 exploitation report (October 12, 2026)