Docker APIを認証なしで2375番ポートへ外部公開すると第三者にコンテナを操作され、ホストまで乗っ取られるおそれがあります。2026年9月22日にThreatDownが報告した「Carbonato」は公開されたDocker APIを悪用して侵入し、到達できる別のDockerホストへ感染を広げるボットネットです。
そもそも2375番ポートって何?
Linux上の一般的なDocker Engineは標準では/var/run/docker.sockというUnixソケットを通じて操作します。Docker APIはコンテナの作成や起動などをDockerデーモンへ指示するための管理用APIです。TCPで待ち受ける設定を追加するとネットワーク越しにこのAPIへ接続できるようになります。
| 接続方法 | ポート | 認証 | 危険度 |
|---|---|---|---|
| Unixソケット(標準) | なし(ローカルのみ) | OSのファイル権限 | 低い(dockerグループの管理は別途必要) |
| TCP(認証なし) | 2375 | なし | 極めて高い |
| TCP(TLS+クライアント認証) | 通常2376 | クライアント証明書 | 証明書と接続元の管理が必要 |
TCPの2375番は平文のDocker REST API、2376番はTLSを使うDocker REST APIのポートとしてIANAに登録されています。ですが2376番へ変更するだけで暗号化や認証が有効になるわけではなく、安全性を決めるのはTLS・クライアント認証の設定と接続を許可する範囲です。
IANAの登録簿の見方や登録された番号と異なるポートでもサービスを動かせる理由はポート番号の割り当てルールを解説した記事で確認できます。

なぜポートが1つ開いているだけでホストを乗っ取られるのか
Docker APIではコンテナの作成時にホストのディレクトリをマウントしたり特権モードを指定したりできます。ホストのプロセス空間やネットワーク空間を共有する設定もあります。これらはそれぞれ別の設定ですが、組み合わせてコンテナを起動するとホスト本体へ広くアクセスできてしまいます。
通常のLinux環境ではDockerデーモンがroot権限で動作するため、認証なしで管理APIを操作できる相手にもホストのroot権限に相当する操作を許してしまいます。この記事ではこの構成を前提に説明します。root権限を使わないRootlessモードでは影響範囲が異なりますが、管理APIを無認証で公開してよいわけではありません。
- Docker自体の脆弱性ではなく正規の機能を悪用されている点が厄介です。パッチを当てても直りません。
- 見直すべき箇所は公開範囲の設定で、ファイアウォールで80番や443番だけ開けているつもりでもクラウドのセキュリティグループ設定を1行間違えるだけで2375番が漏れることがあります。
- 一度侵害されるとコンテナの中だけでなくホスト本体のファイルやプロセスまで触られてしまいます。
Carbonato攻撃に見る、侵害までの4ステップ
ThreatDownの調査によると、Carbonatoは認証なしで公開されたDocker daemonをインターネット上でスキャンし見つけたホストへ次の流れで侵入します。
- 公開された2375番ポートへHTTPでDocker APIのコンテナ作成エンドポイントを直接呼び出す。
- ホストの「/」をまるごとマウントしホストと同じプロセス・ネットワーク空間を共有する特権コンテナを起動する。
nsenterでホストのPID 1(initプロセス)に入り込みコンテナ経由でホスト本体のコマンドを実行する。- 侵入したホストを足がかりに同じネットワーク上で2375番が開いている他のDockerホストを5分おきにスキャンしてワームのように感染を広げる。
侵入後はリバースSSHトンネルによる持続的なアクセス確保、systemdの正規サービスを装ったプロセス名への偽装、cronやsystemdタイマーへの永続化なども確認されています。
さらに、オープンソースのAIエージェントフレームワーク「Hermes Agent」を導入し、Telegram経由で攻撃者が送るタスクをAIモデルが解釈してコマンドを実行する仕組みまで組み込まれている点がこの攻撃の特徴です。窃取対象としてAI関連のAPIキーが最優先で狙われていることも報告されています。
危険なのはDocker自体ではなく、認証なしで外部公開されたAPIが悪用されている点です。
自分の環境で2375番ポートが開いていないか確認する
Windowsから確認する
WindowsのPowerShellで管理しているDockerホストの名前またはIPアドレスを指定します。次のdocker-host.example.comは自分の対象ホストへ置き換えてください。
Test-NetConnection -ComputerName "docker-host.example.com" -Port 2375ComputerName : docker-host.example.com
RemoteAddress : 192.0.2.10
RemotePort : 2375
InterfaceAlias : Ethernet
SourceAddress : 192.168.1.100
TcpTestSucceeded : TrueTcpTestSucceededがTrueならそのPCから対象ホストの2375番へTCP接続できています。とはいえ、この結果では「TCP接続ができている」だけの確認なので「Docker APIが応答しているか」「インターネット全体から到達できるか」までは分かりません。
接続に失敗したときの確認項目やPowerShellのバージョンによるコマンドの使い分けは次の記事で確認できます。

Linuxホストで待ち受けを確認する
Linux上でDocker Engineを動かしている場合はそのホストへログインして実行します。
sudo ss -ltnp 'sport = :2375'State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 0.0.0.0:2375 0.0.0.0:* users:(("dockerd",pid=1234,fd=3))待受アドレスが127.0.0.1や::1ならループバック向け、0.0.0.0や[::]なら各アドレスファミリーの全インターフェース向けです。全インターフェースで待ち受けていても外部から届くかはファイアウォールやルーターなどの設定に左右されます。
Docker APIの応答と外部からの到達を確認する
同じホスト上で、ループバックの2375番から応答するかを確認する例です。
curl --connect-timeout 5 --max-time 10 http://127.0.0.1:2375/version{
"Version": "29.9.0",
"Os": "linux",
"Arch": "amd64"
}Dockerのバージョン情報が返ればこの経路でAPIが応答していることを確認できます。特定のIPアドレスだけで待ち受けている場合はループバックへの接続に失敗することもあります。
外部からの到達を調べる場合は別回線のPCなどから対象ホストの公開IPアドレスまたは公開ホスト名を指定します。次のコマンドはLinux・macOSで実行する例です。
curl --connect-timeout 5 --max-time 10 http://docker-host.example.com:2375/version別の端末でlocalhostを指定するとその端末自身へ接続してしまいます。必ず対象ホストのアドレスへ置き換えてください。
認証情報を渡さずにDockerのバージョン情報が返った場合はその確認元からAPIの情報を取得できています。通常の無認証Docker APIでは管理操作にもつながるため、公開設定を見直してください。読み取り結果だけですべての操作権限まで確認したとは判断しません。
2375番ポートを外部公開しないようにする設定
ここではsystemdで管理しているLinux上のDocker Engineを対象にします。Docker Desktopの設定とは異なります。
すでに外部へ公開している場合はまずクラウドのセキュリティグループやファイアウォールで2375番への接続を遮断します。そのうえでDockerのTCP待ち受けを解除します。Dockerの再起動でコンテナに影響が出る場合があるため、稼働中の処理を確認してから作業してください。
設定されている場所を確認する
sudo systemctl cat docker.service
sudo systemctl cat docker.socketdocker.serviceのExecStartにある-Hまたは--hostの指定を確認します。docker.socket が存在する場合はListenStreamにTCPポートを追加していないかも確認してください。
/etc/docker/daemon.jsonがある場合はhostsの内容も確認します。変更前に編集するファイルのコピーを保存しておいたほうがいいですよ。
TCP待ち受けの指定を外す
起動オプション側で待受先を管理している場合は次のコマンドで上書き設定を編集します。
sudo systemctl edit docker.service既存のExecStartから不要なTCP待ち受けの-H tcp://...を外します。Dockerの実行パスやそれ以外の起動オプションは保持してください。
たとえば現在の起動行が次の場合
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375上書き設定は次の形になります。
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd://これは起動行の例です。実際の設定に--containerdなどの指定がある場合はそれらも残します。
このように起動オプション側で待受先を管理する構成ではdaemon.jsonに重複するhostsを残さないでください。他の設定項目は削除しません。
一方、起動オプションに-Hがなくdaemon.json側で待受先を管理している構成では、hostsから不要なTCPアドレスを外します。通常のLinux環境でUnixソケットだけを残す場合該当項目は次の形です。
"hosts": ["unix:///var/run/docker.sock"]これは既存JSON内の項目の例です。ファイル全体を上書きせず、ほかの設定やカンマの位置を保って編集してください。
docker.socketにも独自のTCP待ち受けを追加していた場合は追加した設定を解除します。
再起動と待ち受け停止を確認する
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl status docker --no-pager
sudo ss -ltnp 'sport = :2375'docker.socketのTCP待ち受け設定も変更した場合はソケット側にも変更を反映します。Dockerを停止するため稼働中のコンテナへの影響を確認してから実行してください。
sudo systemctl stop docker.service docker.socket
sudo systemctl daemon-reload
sudo systemctl start docker.socket
sudo systemctl start docker.service
sudo systemctl status docker.service docker.socket --no-pager
sudo ss -ltnp 'sport = :2375'Dockerが正常に起動し最後のコマンドで2375番の待ち受けが表示されないことを確認します。何も表示されなくてもDocker自体の起動に失敗している場合は対処完了ではありません。
別回線からの接続確認も再実行します。別のポート番号でDocker APIを公開していた場合は、その待ち受けも確認してください。
どうしても外部からDockerを操作したい場合
CI/CDや複数人での共同管理などでどうしてもリモートからDockerを操作する必要がある場合、2375番を素のTCPで開けるのではなく次のどちらかを選びます。
- SSH経由でdocker contextを作る方法。Docker公式でも案内されており、サーバー側にTLS証明書を用意せず、既存のSSH認証の仕組みを使えます。
- TLSクライアント証明書を使う方法(2376番)。HTTP経由でしか接続できないツールと連携する場合はこちらを検討しますが、CA証明書の発行・失効管理まで必要になるため公式ドキュメントでも「TLSとCA管理は高度なトピック」と明記されています。
操作元にはDocker CLIとSSH接続環境が必要です。接続先のユーザーはサーバー上のDockerソケットへアクセスできる必要があります。次の例のユーザー名とホスト名は自分の環境へ置き換えてください。
docker context create \
--docker host=ssh://docker-user@your-server.example.com \
--description="Remote engine" \
my-remote-engine作成した接続先を指定してDockerの情報を確認します。
docker --context my-remote-engine infoいずれの方法でも対象ポートをインターネット全体ではなく特定のIPアドレスからだけ許可するようクラウド側のセキュリティグループやファイアウォールもあわせて絞り込んでおいてください。
迷いやすいポイント
まとめ
- Docker APIを2375番で認証なしに公開すると外部から特権コンテナ経由でホストごと乗っ取られる危険があるよ。
- ホスト上での待ち受けと別回線からの到達を分けて確認してね。外から調べるときはlocalhostではなく対象ホストの公開アドレスを指定するよ。
- 公開が不要なら
daemon.jsonとsystemdの設定からTCP待ち受けを外すのが一番確実だよ。 - どうしてもリモート操作が必要ならTLSよりまずSSH経由のdocker contextを検討してみてね。

