セキュリティ21分で読める

Glassworm攻撃——見えないUnicode文字がGitHub・npmを侵食中

GitHub上の150以上のリポジトリ、npmパッケージ、VS Code拡張機能が、目に見えない文字によって侵害されている——セキュリティ企業Aikidoが2026年3月に報告した「Glassworm」攻撃は、Unicode Private Use Area(PUA)の不可視文字を悪用し、ソースコード上では一切の異常が見えないまま任意コードを実行するサプライチェーン攻撃です。1,460スターを持つ人気リポジトリ「pedronauck/reworm」までもがターゲットとなり、さらにAIを使ったカモフラージュコミットの生成も示唆されています。

2025年3月の初発見から1年、2026年3月に入って大規模な波状攻撃が確認されました。開発者が日常的に使うツールチェーン全体を標的にしたこの攻撃は、従来のコードレビューやセキュリティスキャンでは検出が極めて困難です。

Glassworm攻撃とは何か

Glasswormは、Unicode文字体系の中でもPrivate Use Area(PUA)と呼ばれる領域の文字を悪用した攻撃手法です。PUA(U+E000〜U+F8FF、U+F0000〜U+10FFFF)は、フォントやアプリケーションが独自の用途で使うために予約された領域で、標準的なフォントでは描画されず画面上に表示されません

攻撃者はこの「見えない文字」を悪意あるJavaScriptコードにエンコードし、正常に見えるソースコード内に埋め込みます。具体的な攻撃フローは以下の通りです。

この図は、Glassworm攻撃がペイロードのエンコードからコード実行に至る4つのステップと、GitHub・npm・VS Codeへの拡散経路を示しています。

Glassworm攻撃チェーン — 不可視Unicodeのエンコードからeval()によるコード実行、GitHub・npm・VS Codeへの拡散経路

エンコードの仕組み

攻撃者はまず、悪意あるJavaScriptコード(例: リバースシェルやデータ窃取スクリプト)をPUA文字列に変換します。たとえば、各文字のASCIIコードにPUA領域のベースオフセット(U+E000)を加算することで、通常の英数字を不可視文字に置き換えます。

"malicious code" → [U+E06D, U+E061, U+E06C, U+E069, ...] → (画面上は空白)

この変換後の文字列は、一般的なテキストエディタやGitHubのコードビューでは完全に見えません。空白やスペースとも異なり、カーソルを当てても存在すら気づかないレベルです。

バッククォート内への埋め込み

変換したPUA文字列は、JavaScriptのテンプレートリテラル(バッククォート ` )内に埋め込まれます。テンプレートリテラルはJavaScriptで文字列を定義する正規の構文であり、構文チェッカーやリンターは異常を検出しません。

// 一見すると空のテンプレートリテラルに見える
const data = ``;  // ← 実はPUA文字列が詰まっている

エディタ上では const data = \`;` にしか見えませんが、実際にはバッククォート内に数百〜数千のPUA文字が格納されています。

デコードと実行

postinstall スクリプトや拡張機能のアクティベーション時に、このPUA文字列がデコード関数を通じて元のJavaScriptコードに復元され、eval() で実行されます。デコード処理自体も難読化されており、一見するとユーティリティ関数のように偽装されています。

// デコード関数(簡略化)
function d(s) {
  return [...s].map(c => String.fromCharCode(c.charCodeAt(0) - 0xE000)).join('');
}
eval(d(data));  // PUA文字列 → 元のコード → 実行

この手法の恐ろしさは、ソースコードを目視で確認しても攻撃コードが見えない点にあります。GitHub CopilotのようなAIコーディングアシスタントも、PUA文字を含むコードに対して警告を出すことは現時点ではありません。

感染パッケージと影響範囲

2026年3月12日を中心に、複数のエコシステムで感染パッケージが確認されています。

パッケージ名エコシステム感染バージョン確認日
@aifabrix/miso-clientnpm4.7.23月12日
@iflow-mcp/watercrawl-watercrawl-mcpnpm複数バージョン3月12日
quartz.quartz-markdown-editorVS Code Marketplace0.3.03月12日
pedronauck/rewormGitHub (1,460 stars)汚染PR3月上旬

特に注目すべきは、既存の人気リポジトリが標的にされている点です。pedronauck/rewormは1,460スターを持つReactの状態管理ライブラリで、このようなリポジトリに対してフォーク→悪意あるPR送信→マージを誘導するという手口が確認されています。

AIカモフラージュの脅威

Aikidoのレポートでは、攻撃者がAI(大規模言語モデル)を使って自然に見えるコミットメッセージやPR説明文を生成している可能性が指摘されています。従来のサプライチェーン攻撃では、不自然なコミットメッセージや作りの粗いPRが手がかりになることがありましたが、AIによるカモフラージュはこの人的な検出手段を無効化します。

具体的には以下のような手口が観察されています。

  • 自然なコミット履歴の偽装: 悪意あるコミットの前後に、ドキュメント修正やリファクタリングといった無害なコミットを大量に追加し、実際の開発活動に見せかける
  • もっともらしいPR説明文: 「パフォーマンス改善」「TypeScript型定義の修正」など、メンテナが受け入れやすいテーマでPRを作成
  • コントリビューターのなりすまし: GitHubプロフィールを充実させ、他のOSSプロジェクトへの貢献実績を積み上げることで信頼性を偽装

他のサプライチェーン攻撃との比較

Glasswormは過去のサプライチェーン攻撃と比較して、検出の難しさという点で際立っています。

この図は、SolarWinds、Log4Shell、event-stream、xz Utilsなど過去の主要サプライチェーン攻撃とGlasswormを、攻撃手法・影響範囲・検出難易度で比較しています。

主要サプライチェーン攻撃の比較 — Glassworm、SolarWinds、Log4Shell、event-stream、ua-parser-js、xz Utilsの6件を一覧比較

各攻撃の特徴を詳しく見てみましょう。

比較項目GlasswormSolarWindsxz Utilsevent-stream
攻撃手法不可視Unicode + eval()ビルドシステム侵害長期潜伏型バックドアメンテナ引継ぎ + 依存追加
検出難易度極めて高(目視不可)高(正規ビルド経由)極めて高(2年潜伏)高(依存関係の深さ)
攻撃期間2025年3月〜継続中約9ヶ月約2年約2ヶ月
影響範囲150+リポジトリ18,000組織Linux全般数百万DL
標的JavaScript/Node.js開発者政府・大企業Linuxサーバー暗号通貨ウォレット
AI利用あり(コミット偽装)なしなしなし

Glasswormが特に危険なのは、攻撃インフラのコストが極めて低い点です。SolarWindsやxz Utilsのように高度な技術力や長期間の潜伏が必要なく、PUAエンコーダーさえあれば誰でも攻撃コードを生成できます。しかも検出はSolarWinds級に困難です。

なぜ従来のセキュリティツールでは検出できないのか

Glassworm攻撃が厄介なのは、複数のセキュリティレイヤーをすり抜ける点にあります。

1. 静的解析ツール: ESLintやSemgrepなどの静的解析ツールは、ソースコードの構文パターンを分析しますが、PUA文字は構文上有効な文字列リテラルの内容として処理されます。テンプレートリテラル内の文字列値を「疑わしい」と判定するルールは標準では存在しません。

2. GitHubのコードレビュー: GitHubのdiffビューではPUA文字は表示されないため、PRのレビュー時に変更内容として認識できません。「空の文字列が追加された」ようにしか見えないか、あるいはdiffにすら表示されない場合があります。

3. npm audit / Snyk: パッケージの既知の脆弱性データベースと照合するこれらのツールは、新しい攻撃パターンには対応できません。Glasswormは脆弱性ではなく「悪意あるコード」であり、CVEが割り当てられるまで検出されません。

4. ウイルス対策ソフト: 実行時に初めてデコードされる動的なペイロードは、ファイルスキャン型のウイルス対策では検出困難です。

5. GitHub Dependabot: 依存関係の更新を自動化するDependabotは、既知の脆弱性を持つパッケージバージョンを検出しますが、未知の悪意あるコードは検出対象外です。

検出方法と防御策

Glassworm攻撃に対して、開発者や組織はどのように防御すべきでしょうか。

すぐに実行できる検出方法

Unicodeスキャンコマンド: ソースコード内のPUA文字を検出するには、以下のコマンドが有効です。

# リポジトリ内のPUA文字を検出(U+E000-U+F8FF範囲)
grep -rP '[\x{E000}-\x{F8FF}]' --include='*.js' --include='*.ts' .

# より広範なPUA範囲を含む検出
grep -rP '[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}]' .

VS Codeの設定: VS Codeでは editor.unicodeHighlight.allowedCharacters 設定で不可視文字のハイライトを有効にできます。ただし、PUA範囲のすべてがデフォルトでハイライトされるわけではないため、追加設定が必要です。

Git pre-commitフックの導入

リポジトリにpre-commitフックを設定し、コミット時にPUA文字を自動チェックすることを強く推奨します。

#!/bin/bash
# .git/hooks/pre-commit
if git diff --cached --diff-filter=ACM | grep -P '[\x{E000}-\x{F8FF}]'; then
  echo "WARNING: Unicode Private Use Area characters detected!"
  echo "This may indicate a Glassworm attack. Please review carefully."
  exit 1
fi

パッケージインストール時の対策

npm/yarn: --ignore-scripts オプションでpostinstallスクリプトの実行を無効化できます。ただし、一部のパッケージは正規のpostinstallスクリプトに依存しているため、ホワイトリスト方式での管理が現実的です。

# postinstallスクリプトを無効化してインストール
npm install --ignore-scripts

# 必要なスクリプトだけ手動実行
npx <package-name> postinstall

lockファイルの差分確認: package-lock.jsonyarn.lock の差分を注意深く確認し、意図しない依存関係の追加や変更がないかチェックしてください。

組織レベルの対策

1. SCAツールの導入: Software Composition Analysis(SCA)ツールは、依存関係のリスク評価を自動化します。Aikido Security、Socket.dev、Snykなどが代表的です。特にSocket.devはnpmパッケージの振る舞い分析に特化しており、eval()の使用やネットワークアクセスなどの疑わしいパターンを検出します。

2. 二要素認証の徹底: 1Passwordのようなパスワードマネージャーと組み合わせ、npm・GitHub・VS Codeのアカウントすべてで二要素認証(2FA)を有効化します。npm publishの権限を持つアカウントが乗っ取られると、既存パッケージに悪意あるバージョンを公開される恐れがあるためです。

3. npmパブリッシュの署名: npm provenance(npm v9.5.0以降)を使うと、パッケージのビルドをGitHub Actionsなどの信頼されたCI/CD環境に紐付けることができます。これにより、ローカル環境からの不正なパブリッシュを防止できます。

日本の開発者への影響と注意点

Glassworm攻撃は日本の開発現場にも直接的な影響を及ぼします。

npm依存関係の深さ

日本のWebフロントエンド・バックエンド開発でNode.jsの採用率は高く、一般的なNext.jsプロジェクトでは数百〜数千のnpmパッケージに依存しています。これらの依存関係のどれか一つにGlasswormペイロードが混入するだけで、開発マシンやCI/CDパイプラインが侵害される可能性があります。

OSSへのPR受け入れ体制

日本のOSSプロジェクトの多くは少人数(あるいは個人)でメンテナンスされており、海外からのPRを十分にレビューする体制が整っていないケースが少なくありません。AI生成のもっともらしいPR説明文は、英語力の壁もあり日本人メンテナにとって検出がさらに難しくなります。

CI/CDパイプラインのリスク

GitHub Actionsで npm installnpm ci を実行する際にpostinstallスクリプトが走るため、CI/CD環境自体が攻撃の踏み台になる恐れがあります。特にGitHub ActionsのSecretsに格納されたAPIキーやデプロイ鍵が窃取されると、プロダクション環境への直接的な侵入経路となります。

日本語環境特有の注意点

日本語のソースコードやコメントではUnicode文字が日常的に使われるため、PUA文字の検出ルールを導入する際に日本語テキストとの誤検出に注意が必要です。ただし、PUA領域(U+E000〜U+F8FF)は通常の日本語文字(ひらがな、カタカナ、漢字)とは全く異なる領域にあるため、適切にフィルタリングすれば誤検出は最小限に抑えられます。

eval()のリスクと代替手段

Glassworm攻撃の最終段階で使われる eval() は、JavaScript界隈では以前から「使うべきではない」とされてきた関数です。しかし現実には、動的コード生成やテンプレートエンジンなどの用途で依然として使われています。

Content Security Policy(CSP): Webアプリケーションでは、CSPヘッダーで 'unsafe-eval' を禁止することで、eval()の実行をブロックできます。ただし、Node.jsのサーバーサイドやCLIツールではCSPは適用されません。

Node.js --disallow-code-generation-from-strings: Node.js v11以降で利用可能なこのフラグを使うと、eval()やnew Function()によるコード生成を禁止できます。CI/CD環境のNode.js実行時にこのフラグを付与することで、仮にGlasswormペイロードが混入していても実行を防止できます。

node --disallow-code-generation-from-strings app.js

タイムラインと今後の見通し

Glassworm攻撃の経緯を時系列で整理します。

時期出来事
2025年3月最初のGlasswormサンプルが発見される
2025年中盤散発的な攻撃が確認されるも小規模
2026年3月初旬大規模な波状攻撃が開始
2026年3月12日npm・VS Code Marketplaceで複数の感染パッケージ確認
2026年3月中旬Aikido Securityがレポート公開、150+リポジトリの影響を報告

Aikidoのレポートによれば、攻撃はまだ継続中であり、今後さらに巧妙な亜種が出現する可能性が高いとされています。特にAIを活用した攻撃の自動化は、攻撃の規模と速度を飛躍的に高める恐れがあります。

GitHubやnpmは対策を進めていますが、PUA文字の使用自体はUnicode仕様上「合法」であり、プラットフォーム側で一律にブロックすることは難しい状況です。最終的には、開発者一人ひとりのセキュリティ意識と組織的な防御体制の構築が鍵となります。

まとめ — 今すぐ実行すべき防御アクションステップ

Glassworm攻撃は「目に見えない」という点で前例のないサプライチェーン攻撃です。以下のアクションを今すぐ実行してください。

  1. リポジトリのPUAスキャンを実行する: grep -rP '[\x{E000}-\x{F8FF}]' コマンドで自分のプロジェクト内にPUA文字が混入していないかチェックします。CI/CDパイプラインにもこのスキャンを組み込みましょう
  2. pre-commitフックを導入する: PUA文字を含むコミットを自動的にブロックするGitフックを全リポジトリに設定します。husky等のツールを使えばチーム全体への展開も容易です
  3. npmのpostinstallスクリプトを制限する: npm install --ignore-scripts での運用を検討し、必要なスクリプトだけをホワイトリストで管理します。package-lock.json の差分レビューも習慣化しましょう
  4. アカウントのセキュリティを強化する: npm・GitHub・VS Codeのアカウントで2FAを有効化し、1Passwordで認証情報を安全に管理します。npm publishの権限は最小限のメンバーに限定しましょう
  5. SCAツールを導入する: Socket.devやAikido Securityなどの振る舞い分析型SCAツールを導入し、依存パッケージの異常な振る舞い(eval()使用、ネットワークアクセス等)を自動検出する体制を整えましょう

見えない攻撃に対抗するには、「見えるようにする仕組み」を先手で整えることが最大の防御です。

この記事をシェア