detecting-typosquatting-packages について
ソフトウェアサプライチェーンを守るため、インストール前にパッケージ名を調べるセキュリティスキルです。名前の変異照合、リスク評価、CI/CD への組み込みを扱います。
主な機能
- 01人気パッケージ名との照合
- 02一般的な名前の変異生成
- 03レジストリ情報によるリスク評価
- 04CI/CD ゲートへの組み込み
- 05既知の偽装パッケージデータの参照
活用シーン
- 01依存関係に追加する前の名前確認
- 02AI 生成やチュートリアル由来の依存関係の確認
- 03プルリクエストで新規依存関係を検査
- 04ロックファイル変更に含まれる疑わしい名前の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill detecting-typosquatting-packagesインストール後、Claude Code で/detecting-typosquatting-packagesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdstandards.mdscripts/agent.py詳細
typosquatting パッケージの検出
認可された用途のみ: このスキルは、防御的なソフトウェアサプライチェーンのセキュリティ、パッケージのスクリーニング、および認可を受けた調査を目的としています。ここで説明するコーパスマッチングとレジストリクエリの手法は、大規模な照会が許可されているレジストリに対して、また自組織で評価する意図のあるパッケージに対してのみ使用してください。大量の自動化されたレジストリスクレイピングは、レジストリの利用規約に違反する可能性があります。
概要
Typosquatting は、ソフトウェアサプライチェーン攻撃(MITRE ATT&CK T1195.002 — Supply Chain Compromise: Compromise Software Supply Chain)です。攻撃者は、人気のある正規パッケージに名前がよく似た悪意のあるパッケージを公開します。例として、requests に対する reqeusts、sqlite3 に対する python-sqlite、cross-env に対する crossenv があります。開発者がタイプミスで名前を誤入力したり、汚染されたチュートリアルから名前をコピーしたり、AI が生成した依存関係リストを信頼したりすると(「slopsquatting」と呼ばれる亜種です。モデルが存在しないパッケージ名を幻覚し、攻撃者がそれを登録します)、正規のパッケージではなく squat パッケージをインストールしてしまいます。多くのエコシステムではインストール時スクリプト(npm の postinstall、PyPI の setup.py/ビルドフック)が実行されるため、ペイロードは開発者の権限で即座に実行されます。
このスキルでは、インストール前に行う能動的な検出を扱います。攻撃者が使うのと同じ名前変異のプリミティブを用いて、候補パッケージ名を人気のある既知の正規名のコーパスと照合し、リスクの高いマッチをトリアージします。代表的なオープンソースの検出ツールは typomania(Rust Foundation)です。これは学術ツール typogard(「Defending Against Package Typosquatting」、カンザス大学)の Rust 移植版で、crates.io のライブ typosquatting チェックを支えています。エコシステムを横断するカバレッジは、Microsoft OSSGadget の oss-find-squats と、PyPI 向けの IQTLabs pypi-scan から得られます。ecosyste-ms の typosquatting-dataset は、既知の squat と正規の対象との対応を示す、キュレーションされた正解データのコーパスを提供します。
出典: Rust Foundation typomania(https://github.com/rustfoundation/typomania)、Microsoft OSSGadget、ecosyste-ms typosquatting-dataset、および OWASP CI/CD / SLSA のサプライチェーンガイダンス。
使用するタイミング
package.json、requirements.txt、pyproject.toml、Cargo.tomlに新しい依存関係を追加する前- プルリクエストで新しく導入されたすべての依存関係名をスクリーニングする CI/CD ゲートとして
- AI が生成した、またはチュートリアル由来の依存関係リストをトリアージするとき(「slopsquatting」レビュー)
- ロックファイルの差分をセキュリティレビューする際に、入れ替えられた squat や新たにピン留めされた squat を見つけるとき
- 疑わしい squat のインストールをブロックするレジストリ側またはプロキシ側のガードレールを構築するとき
前提条件
- typomania をビルド・使用するための Rust ツールチェーン(
cargo)、または OSSGadget のビルド済みリリース - pypi-scan とこのスキルのヘルパースクリプトのための Python 3.8 以上
- 対象レジストリの公開 API(npmjs.org、pypi.org、crates.io)へのネットワークアクセス
- エコシステムの「人気のある」パッケージ名のコーパス(ダウンロード数または上位 N 件のリスト)
ツールをインストールします:
# typomania (library + example harness) — Rust Foundation
git clone https://github.com/rustfoundation/typomania
cd typomania
cargo build --release
cargo run --example registry # demonstrates the Harness against a fake registry
# OSSGadget (Microsoft) — cross-ecosystem squat finder
# Download a release binary, then:
oss-find-squats pkg:npm/requests # purl syntax
oss-find-squats pkg:pypi/reqeusts
# pypi-scan (IQTLabs) — PyPI typosquat enumerator
git clone https://github.com/IQTLabs/pypi-scan
cd pypi-scan
pip install -r requirements.txt
# ecosyste-ms ground-truth dataset of known squats
git clone https://github.com/ecosyste-ms/typosquatting-dataset
目的
- 標準的な変異プリミティブを用いて、特定の正規名に対する候補 squat の集合を生成する
- 候補パッケージ名を人気のある名前のコーパスと照合し、類似度の高いものを検出する
- 疑わしい各 squat をレジストリのメタデータ(作成からの経過期間、ダウンロード数、メンテナー、インストールスクリプト)で補強する
- 検出結果をスコア付けしてトリアージし、誤検知(正当なフォークやスコープ付きパッケージ)を抑制する
- チェックを CI/CD に組み込み、新しい依存関係をブロックするゲートとして機能させる
MITRE ATT&CK マッピング
| Technique ID | Name | Tactic |
|---|---|---|
| T1195.002 | サプライチェーンの侵害: ソフトウェアサプライチェーンの侵害 | 初期アクセス |
typosquat された依存関係は T1195.002 の配送手段となります。攻撃者は正規のパッケージを侵害するのではなく、悪意のある酷似パッケージを代わりにインストールさせることで、被害者のサプライチェーンを侵害します。関連する後続の挙動として、インストールフックによる T1059(コマンドおよびスクリプトインタプリタ)や、トークンおよび環境変数の窃取による T1041/T1567(流出)が頻繁に見られます。
ワークフロー
Step 1: 人気パッケージ名のコーパスを構築する
検出器には、比較対象となる正当な名前の参照セットが必要です。エコシステムごとにダウンロード数の多い上位パッケージを取得します。
# PyPI: top packages dataset (Hugo van Kemenade's top-pypi-packages)
curl -s https://hugovk.github.io/top-pypi-packages/top-pypi-packages.min.json \
-o top-pypi-packages.json
# npm: query the registry's most-depended-upon search
curl -s 'https://registry.npmjs.org/-/v1/search?text=not:unstable&popularity=1.0&size=250' \
-o npm-top.json
# crates.io: top crates by downloads
curl -s 'https://crates.io/api/v1/crates?sort=downloads&per_page=100' \
-H 'User-Agent: typosquat-screen ([email protected])' -o crates-top.json
Step 2: 標準的な変異プリミティブで候補となるスクワッティング名を生成する
typomania/typogard は、実際の攻撃者の振る舞いを反映した一連の名前変換を固定的に適用します。スクリーニングで何を検出すべきかを理解するために、これらを再現します:
1. Repeated characters requests -> reqquests
2. Omitted characters requests -> requsts
3. Swapped/transposed requests -> reqeusts
4. Swapped words python-dateutil -> dateutil-python
5. Common typos (1-edit) requests -> rewuests (keyboard adjacency)
6. Homophones / vowel swap requests -> requeasts
7. Version / suffix tricks lodash -> lodashs, lodash-js
8. Delimiter swaps cross-env -> crossenv, cross_env
9. Scope confusion (npm) @types/node -> types-node
typomania のハーネスを実行します。これは Corpus と Harness トレイトの背後で、これらを再利用可能なプリミティブとして実装しています:
# In the typomania checkout: feed your popular corpus, then check a name.
# The Harness::check method (parallelized via rayon) compares the candidate
# against every corpus entry using the squatting primitives.
cargo run --example registry -- --corpus top-pypi-packages.json --name reqeusts
Step 3: OSSGadget oss-find-squats でスクリーニングする
OSSGadget はライブレジストリに問い合わせ、指定されたパッケージの変異名を生成し、そのうちどの変異名が実際に公開パッケージとして存在するかを報告します。
# Find names that squat on a legitimate package, checking which exist in the registry
oss-find-squats pkg:npm/lodash
oss-find-squats pkg:pypi/requests
# Reverse direction: given a SUSPECT name, find the legitimate package it mimics
oss-find-squats --quiet pkg:npm/loadsh
Step 4: pypi-scan で PyPI のスクワッティングを列挙する
cd pypi-scan
# Find candidate typosquats of a specific package
python pypi_scan.py -p requests
# Scan the top-N most-downloaded PyPI packages for existing squats
python pypi_scan.py -n 50
Step 5: レジストリのメタデータで疑わしいスクワッティング候補を補強する
名前が少し似ているだけでは、疑わしいとは言えません。新しい、ダウンロード数が少ない、またはインストールスクリプトを含む場合に初めて疑わしくなります。メタデータを取得してトリアージします:
# npm package metadata: creation time, maintainers, scripts
curl -s https://registry.npmjs.org/loadsh | \
python -c 'import sys,json;d=json.load(sys.stdin);v=d["dist-tags"]["latest"];print("created:",d["time"]["created"]);print("scripts:",d["versions"][v].get("scripts",{}))'
# npm download counts (last week)
curl -s https://api.npmjs.org/downloads/point/last-week/loadsh
# PyPI JSON API: release history and author
curl -s https://pypi.org/pypi/reqeusts/json | \
python -c 'import sys,json;d=json.load(sys.stdin);i=d["info"];print(i["name"],i["author"],i["home_page"]);print("releases:",list(d["releases"].keys()))'
Step 6: スコアリング、トリアージ、確認を行う
シグナルを組み合わせてリスクスコアを算出します。高リスク = 人気名との編集距離が小さい AND(パッケージの公開から90日未満 OR ダウンロード数 < 1000 OR postinstall/preinstall/セットアップ時のネットワーク呼び出しが存在する)。ecosyste-ms の既知スクワッティングデータセットと照合します:
# Is this name a documented squat?
grep -i 'loadsh' typosquatting-dataset/data/*.csv
悪意の有無は、(サンドボックスまたは VM 内でのみ)インストールスクリプトとソースの tarball を調べて確認します。疑わしいパッケージを、ワークステーション上で npm install や pip install してはいけません。
Step 7: CI/CD で強制する
PR で導入される新しい依存関係名をすべてスクリーニングするブロッキングゲートを追加します:
# .github/workflows/typosquat-gate.yml
name: typosquat-gate
on: [pull_request]
jobs:
screen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Screen new dependencies
run: |
git diff origin/${{ github.base_ref }}...HEAD -- package.json requirements.txt \
| grep '^+' | python scripts/agent.py screen --ecosystem npm --corpus top.json --stdin
ツールとリソース
| Tool | Purpose | Source |
|---|---|---|
| typomania | Rust typosquat-detection library (powers crates.io) | https://github.com/rustfoundation/typomania |
OSSGadget oss-find-squats | Cross-ecosystem squat finder (purl) | https://github.com/microsoft/OSSGadget |
| pypi-scan | PyPI typosquat enumerator | https://github.com/IQTLabs/pypi-scan |
| ecosyste-ms typosquatting-dataset | Curated known-squat ground truth | https://github.com/ecosyste-ms/typosquatting-dataset |
| top-pypi-packages | PyPI popular-name corpus | https://hugovk.github.io/top-pypi-packages/ |
| OWASP CI/CD Security Top 10 | Supply-chain control guidance | https://owasp.org/www-project-top-10-ci-cd-security-risks/ |
変異プリミティブのリファレンス
| Primitive | Legit | Squat | Why it works |
|---|---|---|---|
| Transposition | requests | reqeusts | Common typing slip |
| Omission | requests | requsts | Dropped character |
| Repetition | requests | reqquests | Stuck key |
| Delimiter swap | cross-env | crossenv | Hyphen vs none ambiguity |
| Word order | python-dateutil | dateutil-python | Reordered compound name |
| Homoglyph/vowel | requests | requeasts | Visual/phonetic similarity |
| Suffix/scope | lodash | lodash-js, loadsh | Plausible "official" variant |
検証基準
- 対象となる各エコシステムについて、人気名のコーパスをダウンロードした
- 変異プリミティブを再現し、既知のスクワッティング名(例:
loadsh)が正しくフラグされることを確認した - typomania / OSSGadget / pypi-scan を、少なくとも1つの実際のパッケージに対して実行した
- 疑わしいスクワッティング候補を、公開からの期間、ダウンロード数、インストールスクリプトのメタデータで補強した
- 検出結果を ecosyste-ms の既知スクワッティングデータセットと照合した
- リスクスコアリングにより、明らかな誤検出(正当なスコープ付きパッケージやフォークしたパッケージ)が抑制されている
- CI/CD ゲートが、すべてのプルリクエストで新しい依存関係名をスクリーニングしている
- 疑わしいパッケージを、使い捨てのサンドボックス外にインストールしていない