I got hacked: My Hetzner server started mining Monero

2025/12/18 6:13

I got hacked: My Hetzner server started mining Monero

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

ヘツナー VPS 上で Coolify をホストし、Next.js ベースの Umami アナリティクスを含む複数コンテナを実行していた。12 月 7 日に、Umami コンテナ内に Monero マイニングボット(

javae
/
xmrig
)が出現し、CPU スパイクが約 15 倍に増大した。著者はマイナーをコンテナに追跡し、CVE‑2025‑66478 ― Next.js の React Server Components “Flight” プロトコルにおける不安全なデシリアライゼーション(Puppeteer を介さずリモートコード実行が可能)を特定した。HTTP リクエストを巧妙に作成することで RCE が発動し、マイナーがインストールされた。ホストファイルシステムのチェック(
/tmp/.XIN-unix/javae
)ではエスケープは確認できず、コンテナは非 root の
nextjs
ユーザーとして実行され、特権モードやボリュームマウントも無いため、すべての悪意あるプロセスは名前空間内に留まった。

著者は侵害されたコンテナを停止・削除し、CPU 負荷を通常状態へ戻した。UFW をデフォルトで受信トラフィックを拒否するよう設定し、SSH、HTTP、および HTTPS のみ許可することで、オープンな PostgreSQL / RabbitMQ ポートを効果的に遮断した。ヘツナーは 2025‑12‑17 にネットワークスキャン検知後、アブズケース警告を送付し、著者が侵害と対策を説明するとともにチケットはクローズされた。

重要な教訓として、十分に隔離されているコンテナでも基盤フレームワークに脆弱性がある場合は突破可能であり、「Next.js を使っていない」状態が第三者ツールの依存関係によって偽りになるケースがあることを指摘した。この事例は、ファイアウォールルール、非 root ユーザー設定、特権モード無し、監視・ fail2ban の導入、およびタイムリーなパッチ適用という防御層の重要性を強調した。

行動計画

  • Umami を廃止する
  • すべてのコンテナに対してユーザー権限とマウントを監査する
  • SSH アクセスを強化し、アラートを設定する
  • セキュリティパッチを定期的に適用し、将来のインシデントを防止する

本文

編集:
HN の数名の方から「この記事は少し LLM が生成したように聞こえる」と指摘されました。実際には私がパニックになって Claude と話している様子をトランスクリプト化したものですので、読みづらい点があればすみません ― 事件は本当に起きたことです!


「Next.js を使わない」っていうのは「あなたの依存関係が Next.js を使っていない」という意味ではないと知った経緯

午前8:25 – メール

Hetzner からこんなメールで目覚めました:

Dear Mr Jake Saunders,

We have indications that there was an attack from your server. Please take all necessary measures to avoid this in the future and to solve the issue.

We also request that you send a short response to us… The attached evidence shows network scanning from my server to some IP range in Thailand.

「おはよう」よりも、インフラを 4 時間以内に停止させる脅威がある方がずっと怖いですね。

背景: 私は Hetzner のサーバーで Coolify を動かしています。そこには以下のサービスがあります:

  • IoT サイドプロジェクト
  • このブログ
  • アナリティクス
  • 父親の電気工事サイト

午前8:30 – まずは…

最初にやったことは SSH でサーバーに接続し、負荷平均を確認することでした:

$ w
 08:25:17 up 55 days, 17:23, 5 users, load average: 15.35, 15.44, 15.60

通常の負荷は 0.5–1.0 程度なのに、15 は明らかに異常です。

ps aux
を実行すると:

USER      PID %CPU %MEM VSZ   RSS TTY      STAT START   TIME COMMAND
1001    714822 819 3.6M 2464788 2423424 ? Sl Dec16 9385:36 /tmp/.XIN-unix/javae
...

javae
と名付けられたプロセスが
/tmp/.XIN-unix/
内で CPU を 819 % 使用し、さらに
xmrig
プロセスも複数走っていました ― 文字通り暗号マイニングソフト(Monero)です。

12 月 7 日から誰かのためにマイニングしていたので、10 日間で CPU が 1000 %+ を占めていました。


調査

最初は「もうダメだ」と思いましたが、すべてのプロセスが ユーザー 1001 として実行されていることに気付きました。root やシステムユーザーではありませんでした。

$ docker ps -q | while read container; do
    echo "=== $container ==="
    docker exec $container ls -la /app/node_modules/next/dist/server/lib/ 2>/dev/null | grep xmrig
done

出力:

=== a42f72cb1bc5 ===
drwxr-xr-x 2 nextjs nogroup 4096 Dec 17 05:11 xmrig-6.24.0

これは Umami アナリティクスコンテナです。マイニングコマンドは次の通りでした:

/app/node_modules/next/dist/server/lib/xmrig-6.24.0/xmrig \
  --url auto.c3pool.org:443 \
  --user <wallet> \
  --pass <password> \
  --donate-level 0

誰かが私のアナリティクスコンテナを乗っ取り、CPU を使って Monero をマイニングしていたのでした。


「Next.js を使わない」― その落とし穴

数日前に Reddit で CVE‑2025‑66478(Next.js/Puppeteer の重大な RCE)についての記事を見ました。すぐに「私は Next.js を走らせていない」と思って笑いました。

しかし Umami は Next.js で構築されており、脆弱性は Next.js の React Server Components (RSC) のデシリアライズ(“Flight” プロトコル)にあります。攻撃者は任意の App Router エンドポイントへ悪意ある HTTP リクエストを送ることでサーバー上でコードを実行できます。

攻撃フロー:

  1. 攻撃者が Umami の Next.js エンドポイントへ偽造リクエストを送信
  2. RSC が悪意のペイロードをデシリアライズ
  3. 任意コード実行
  4. 暗号マイナーをダウンロード・インストール
  5. 利益獲得

マルウェアはコンテナから抜けたか?

/tmp/.XIN-unix/javae
というプロセスリストはホストパスのように見えます。もしホスト上に存在していれば、マルウェアは逃げていたことになります。

$ ls -la /tmp/.XIN-unix/javae
ls: cannot access '/tmp/.XIN-unix/javae': No such file or directory

実際にはホスト上にはありませんでした。Docker は

ps aux
にコンテナプロセスを表示しますが、マウント namespace で隔離されているため、ホストファイルシステムに触れることはできません。

コンテナの詳細:

$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep '"User"'
"User": "nextjs",

$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep '"Privileged"'
"Privileged": false,

$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep -A 30 "Mounts"
"Mounts": [],

マルウェアができること:

  • コンテナ内で動作
  • 暗号を採掘
  • ネットワークスキャン(Hetzner のレポート原因)
  • CPU を消費

できないこと:

  • ホストファイルシステムへアクセス
  • cron や systemd サービスの設置
  • 再起動後も残る
  • 他コンテナへ移行
  • ルートキットをインストール

結果として、コンテナ隔離は機能しました。よかったです。


重要性 – Dockerfile と自動生成イメージの違い

私は自分で Dockerfile を書いています。Nixpacks のようにデフォルトで

USER root
に設定される自動生成ツールは使いません。root で走っていた Reddit ユーザーのコンテナは、cron や systemd サービスを設置できたためサーバー再起動後も継続していました。


修復手順

  1. 侵害されたコンテナを削除

    $ docker stop umami-bkc4kkss848cc4kw4gkw8s44
    $ docker rm umami-bkc4kkss848cc4kw4gkw8s44
    
  2. CPU 使用率の確認

    $ uptime
      08:45:17 up 55 days, 17:43, 1 user, load average: 0.52, 1.24, 4.83
    
  3. UFW(Uncomplicated Firewall)を有効化

    $ sudo ufw default deny incoming
    $ sudo ufw default allow outgoing
    $ sudo ufw allow ssh
    $ sudo ufw allow 80/tcp
    $ sudo ufw allow 443/tcp
    $ sudo ufw enable
    
  4. Hetzner に報告

    Investigation complete. The scanning originated from a compromised Umami analytics container (CVE‑2025‑66478 - Next.js/Puppeteer RCE). 
    The container ran as non-root user with no privileged access or host mounts, so the compromise was fully contained. 
    Container removed and firewall hardened.
    

Hetzner は 1 時間以内にチケットをクローズしました。


学んだこと

  1. 依存関係が本当に何を使っているか確認する
    「X を使わない」だけでは安全とは限らず、サードパーティツールでも X が内部で使用されている可能性があります。

  2. 適切に設定すればコンテナ隔離は機能する
    root ユーザーを避け、privileged モードや不要なマウントをしないようにし、自前の Dockerfile を書くことが重要です。

  3. 高度化されたマルウェアも境界で制限される
    悪意あるパスや偽装プロセス名は使われていたものの、コンテナ境界によって影響範囲が限定されました。

  4. 防御の重層化が重要
    – 早期にファイアウォール設定
    – Fail2Ban による SSH ブルートフォース対策
    – CPU 負荷やネットワーク活動の監視/警告
    – CVE 公開時の即時更新


今後の方針

  • Umami は廃止し、Go ベースの代替(GoatCounter など)を検討中
  • すべてのサードパーティコンテナを監査:ユーザー、ボリューム、アップデート状況、必要性
  • SSH を鍵認証のみで強化、パスワード認証無効化、Fail2Ban を導入
  • CPU 使用率・負荷平均・ネットワーク活動の適切な監視とアラート設定
  • 定期的にセキュリティアップデートを実施し、脆弱性が判明したら即座にパッチまたは削除

奇妙な銀色の裏返し

本当に侵害された際にインシデントレスポンスを実践できたこと、コンテナ隔離が機能することを証明できたこと、Docker の namespace と権限境界について学べたこと、そしてデータ損失なしでインフラを強化できたこと。仕事の前に 2 時間ほど奪われただけでした――もっと悪い事態になっていた可能性もありました。


TL;DR

  • Umami(Next.js ベース)に Puppeteer RCE が存在
  • 攻撃され、10 日間 Monero をマイニングする暗号マイナーが稼働し、CPU 1000 %+ 使用
  • コンテナは非 root でマウント無しだったため隔離に成功
  • 対策:
    docker rm umami
    、ファイアウォール有効化
  • 教訓:依存関係を正確に把握し、コンテナ設定を適切に行うこと。

同じ日のほかのニュース

一覧に戻る →

2025/12/18 1:42

Gemini 3 Flash: Frontier intelligence built for speed

## Japanese Translation: > **概要:** > Google は、低コストで高速な AI モデル Gemini 3 Flash をリリースしました。これは Flash レベルのレイテンシーでプロ級の推論性能を提供します。Gemini アプリと Search の AI Mode では既にデフォルトエンジンとなり、Gemini 2.5 Flash は世界中で追加料金なしで即座に置き換えられます(Gemini 3 Pro が公開された直後)。ベンチマーク結果では、GPQA Diamond で 90.4 %、Humanity’s Last Exam(ツール無し)で 33.7 %、MMMU Pro で 81.2 %、SWE‑bench Verified で 78 % を獲得し、より大きなフロンティアモデルを上回ります。Gemini 3 Flash は Gemini 2.5 Pro より約30 %少ないトークン数で同等以上の性能を発揮します。価格は入力トークンあたり 0.50 USD、出力トークンあたり 3 USD(音声入力は 1 USD/百万トークン)です。JetBrains、Bridgewater Associates、Figma など多くの企業がこのモデルを活用し、コーディング、データ分析、設計ワークフローの高速化に役立てています。開発者は Gemini API(Google AI Studio)、Antigravity、Gemini CLI、Android Studio、Vertex AI、および Gemini Enterprise を通じて Gemini 3 Flash にアクセスできます。このモデルは Gemini アプリと Search 経由で全ユーザーへ展開されるほか、プレビュー API でも利用可能です。

2025/12/18 3:15

How SQLite is tested

## Japanese Translation: > **SQLiteのテストインフラは網羅的で、コードベース全体にわたって完全な分岐カバレッジを実現しています。** > プロジェクトには約155.8 KSLOCのCソースがありますが、テストコードは92 M KSLOC以上――約590倍の量――で、すべての行が実行されることを保証しています。4つの独立したハーネスがカバレッジを提供します: > • **TCL**(27.2 KSLOC、1,390個のスクリプトファイル)で51,445件の異なるケースと数百万回の実行があります; > • **TH3**(1,055.4 KSLOC、約76.9 MBのバイナリ)で50,362件の異なるケース、完全カバレッジに必要な2.4 Mインスタンス、および約248.5 Mテストを実行するソークテストがあります; > • **SQL Logic Test (SLT)** はSQLiteとPostgreSQL、MySQL、MS SQL Server、Oracle 10gを比較し、7.2 Mクエリと1.12 GBのデータで検証します; > • **dbsqlfuzz**(libFuzzerベース)はSQLとデータベースファイルの両方を変異させ、約336個のシードファイルから16コアで1日あたり約500 Mテストを提供します。 > 追加の軽量ハーネスには `speedtest1.c`、`mptester.c`、`threadtest3.c`、`fuzzershell.c`、およびJSONBファズラ `jfuzz` が含まれます。 > 異常テストではメモリ不足、I/O障害、クラッシュ/電源損失、およびカスタムmalloc/VFSフックを使用した複合故障をシミュレートし、各障害後に整合性チェックが実行されます。 > ファズリングの歴史はAFL(2014‑2019)からOSS Fuzz(2016年以降)、その後dbsqlfuzz(2018年末)とjfuzz(2024年1月)へ進化しました。`fuzzcheck` スクリプトは毎回ビルド時に興味深いケースを再実行し、新しいバグが自動的にリグレッションテストとして生成されることを保証します。 > リソースリーク検出はTCL/TH3ハーネスに組み込まれており、メモリリーク、ファイルディスクリプタ枯渇、および不要なスレッドが自動的に監視されます。 > カバレッジは `gcov` を使用して100 %の分岐カバレッジと変異テストで達成され、マクロ(`ALWAYS`、`NEVER`、`testcase`)がMC/DCを強制し、コメント(`/*OPTIMIZATION‑IF‑TRUE/FALSE*/`)は偽陽性を防ぎます。 > 結果として、継続的に拡張される高い信頼性のテストスイートが実現し、ユーザーにSQLiteの安定性への確信を提供し、セキュリティ脆弱性から保護し、オープンソースデータベース品質保証のベンチマークとなります。

2025/12/18 5:50

Inside PostHog: SSRF, ClickHouse SQL Escape and Default Postgres Creds to RCE

## Japanese Translation: 記事は、PostHog のサーバー側リクエストフォージェリ(SSRF)欠陥を複数段階の攻撃チェーンに変えて、PostgreSQL データベースでリモートコード実行を可能にする方法を説明しています。研究者は 24 時間を費やしてソースレベルで手動調査を行い、その結果、オープンソース性と高速 Docker 配備が特徴の自己ホスト型分析プラットフォームとして PostHog を選択しました。 PostHog の Rust Webhook ハンドラー、`database_schema`、および `slack_incoming_webhook` で三つの SSRF 脆弱性(CVE‑2024‑9710、CVE‑2025‑1522、CVE‑2025‑1521)が特定されました。`test_slack_webhook` エンドポイントは URL を検証しますが、`save` エンドポイントでは検証が行われません;PATCH リクエストでこのチェックを回避し、`localhost` のような内部アドレスを保存できます。その後 Rust Webhook ワーカーがこれらの保存された URL に対して再検証なしに POST を送信し、HTTP リダイレクトを追跡して内部的に POST を GET に変換します。 PostHog の ClickHouse バックエンドはポート 8123 上で認証不要な HTTP API を公開しています。GET 要求は読み取り専用ですが、テーブル関数 `postgresql()` はリモート PostgreSQL クエリを許可します。ClickHouse はこの関数内のシングルクォートをバックスラッシュ(`\`)で誤ってエスケープし、テーブル名にエスケープされていない引用符が含まれると SQL インジェクションベクトルを作成します。 COPY 文を閉じ、`;END;` でトランザクションを終了し、ドル引用符で囲まれた PostgreSQL の `COPY FROM PROGRAM` 構文を使用したペイロードを構築することで、攻撃者はリモート PostgreSQL サーバー上で任意の OS コマンドを実行できます。完全なエクスプロイトチェーンは次の通りです: (1) PATCH による Webhook URL 検証回避、 (2) Rust ワーカー内の SSRF、 (3) POST‑to‑GET リダイレクト変換、 (4) ClickHouse SQL インジェクション、 (5) `;END;` と `COPY FROM PROGRAM` を含むペイロード構造、 (6) 追加エスケープを避けるためのドル引用符、 (7) 静的 Docker 名称/認証情報への依存。 研究者は Python スクリプト(`rust-webhook-ssrf-rce.py`)で脆弱性を実演しました。脚本は認証し、`localhost` を指す悪意ある Webhook を作成してトリガーし、PostgreSQL コンテナ内にリバースシェルを取得します。彼らは 2024‑10‑03 に ZDI 経由で責任ある報告を行い、アドバイザリーが公開され 2025‑02‑25 に更新されました。 自己ホスト型 PostHog ユーザーおよび ClickHouse を分析に利用している企業は、これらの脆弱性をパッチしない場合深刻なリスクに直面します。この事件は Webhook URL の検証、内部 API の保護、およびデータベース関数でのユーザー入力の正しいエスケープの重要性を強調しています。