「大変だ!! Claude Codeのソースコードが漏洩したらしい!!どうやら.mapファイルをnpmにアップロードしてしまったようだ」
??? 「えっ!!!大変じゃないですか!!!ところで、
.mapファイルってなんですか??
使ったことない。何それうまいの?と思い自戒も込めて調べてみる
マップファイルとは?
.mapファイルは「ソースマップ(source map)」と呼ばれるもので、MDNによると以下のように記載されている。
ブラウザが受信した縮小または変換されたコードと、元の変更されていないコードとの間のマッピングを行うJSONファイル形式であり、デバッグ時に元のコードを再構築して使用できるようにするもの
これは何のために必要かというと、以下のようなビルド処理が前提にある。
- ファイルの結合や圧縮による配信効率の向上
- 新しい構文を古いブラウザ向けに変換(トランスパイル)
- TypeScript や Sass などの非ネイティブ言語の利用
このような変換が入ると、ブラウザで実行されるコードと、開発者が書いた元コードの対応関係が崩れる。
その対応関係を記録しているのが ソースマップ である。
つまり、圧縮されたコードと、元のコードの対応表らしい。確かに名前の通りマップ🗺️的な役割だ。
それが今回なんで利用されていたの?と思って調べたら、Google公式系の情報サイトであるweb.devに活用方法が載っていた。この動画、英語だけどめちゃくちゃ分かりやすかったのでおすすめだ。自動翻訳で日本語字幕も出せる。
上記サイトによると、コードを圧縮するとパフォーマンスは上がるが、デバッグが難しくなるという欠点がある。
たとえば、ビルドツールを使用して、次の TypeScript ファイルをトランスパイルする
/* A TypeScript demo: example.ts */
document.querySelector('button')?.addEventListener('click', () => {
const num: number = Math.floor(Math.random() * 101);
const greet: string = 'Hello';
(document.querySelector('p') as HTMLParagraphElement).innerText = `${greet}, you are no. ${num}!`;
console.log(num);
});
これは以下のような1 行の JavaScript に圧縮される
/* A compressed JavaScript version of the TypeScript demo: example.min.js */
document.querySelector("button")?.addEventListener("click",(()=>{const e=Math.floor(101*Math.random());document.querySelector("p").innerText=`Hello, you are no. ${e}!`,console.log(e)}));
これはまだ短いのでなんとかなるかもしれないが、1行のコードからピンポイントでデバッグするのは難易度が高いのがイメージできる。
つまり、ソースマップがあることで、コンパイルされたコードを元のコードにマッピングし直し、エラーの原因をすばやく見つけることができる
そして、ソースマップの実態が、今回話題の名前が .map で終わるファイルなのである。
.map ファイルにはこういう情報が入っている
{
"version": 3,
"file": "add.js",
"sources": ["../src/add.ts"],
"sourcesContent": [
"export function add(a: number, b: number) { return a + b; }"
],
"mappings": "AAAA..."
}
sources:元ファイルのパス
sourcesContent:元コードそのもの(含まれる場合あり)
mappings:変換後コードと元コードの位置対応
特に sourcesContent が含まれている場合、元のソースコードがそのまま格納されている。
ここまで理解すると、
そりゃソースコードをアップロードしたようなものでは?
という感覚はかなり同意できる。
というか、自分は使ったことがないと思っていたが、 example.min.js.map、styles.css.mapみたいなのdist/にコンパイルされてるのを見たことあるのに気づいた...
ビルドツール(Vite / Webpack / esbuild など)が自動生成するものなので開発者が明示的に触らないため、存在を意識しないまま使っていることが多い。
私もやりかねない...理解してないって怖い...明日は我が身だ。
今回のClaude Codeでは何が漏洩した?
画像を見ると、cli.js.mapが見えてしまっている。
さらにサイズが数十MBと大きく、
単なるマッピングではなく
sourcesContent を含む可能性が高い
つまり、元のソースコードをほぼそのまま取得できる状態だった可能性がある
これをどう復元するのか。方法はいくつかあるそうだ。
.mapファイルからソースコードを復元する方法
方法1:.mapファイルをそのまま開く
一番簡単な方法。
"sourcesContent"に元のソースコードがそのまま入っている場合があるのでこれを見る
方法2:ツールを使う
source-map-explorer などのツールを使うと、
- ファイル構成
- モジュール単位のサイズ
- ソースコード
を可視化できる。
npm install -g source-map-explorer
source-map-explorer cli.js cli.js.map
方法3:Chrome DevToolsで復元
cli.jsとcli.js.mapを同じ場所に置き、ブラウザで読み込む。
すると、元のTypeScriptや元ファイル構造がそのまま表示される。
これはブラウザがSourceMapを使って「圧縮コード → 元コード」を自動で復元しているためだ。
つまり、開発者ツール = 復元ツールでもある。
なぜnpmに.mapを入れてしまう事故が起きるのか
実はかなりよくある事故らしい。
原因はシンプルで、
- ビルド時に自動生成される
- dist/ をそのまま publish する
- .npmignore や files 設定をしていない
特に npm は:
package.json の files
.npmignore
で制御しない限り、ビルド成果物がそのまま含まれる。
対策として、
- 本番ビルドでは source map を無効化
- もしくは公開対象から除外する
- .npmignore または files を適切に設定する
- そもそもフロントコードに機密情報を書かない
ことが重要である。
まとめ
- .map は変換後コードと元コードの位置対応を記録したデータ
- 配布物に含めると、元コードの構造や内容が取得可能になるケースがある
- デバッグには有用だが、公開範囲や配布対象は意図的に制御する必要がある
今回の件で自分も知らないうちに公開している可能性があると知れたので良かった。
AIや便利なツール・パッケージ頼りで、基礎的なことを理解せずに使っているものは多いが、今後も自分から興味を持って知ろうとすることを大切にしていきたいと感じた。