Tailscaleの脆弱性レポート「Tailworm」11件の対処法|修正版が出るまでにやること
目次
Tailscale の基本的な使い方は「自宅PCをTailscaleで繋ぐSSH接続チュートリアル」に、スマホから SSH する全体像は「モバイルSSH完全ガイド」にまとめています。この記事は、2026年10月に出た脆弱性レポートへの守る側の対処だけを扱います。
この記事の要点(30秒)
- 2026年10月25日、研究者が Tailscale と headscale の問題 11件 をまとめたレポート「Tailworm」を公開した。Tailscale は翌26日に問題を認め、10月28日の 1.104.4 で修正した(headscale は 0.29.7)。全端末を 1.104.4 以上に更新する(2026年11月6日に確認)
- いちばん重いのは Tailscale SSH。SSH を許可された端末が1台乗っ取られると、ほかのサーバーまで被害が広がりうる
- 効き目が一番大きい対策は、SSH を許可するルールを「この端末からこの端末へ」の組み合わせ単位に絞ること。使わない端末では Tailscale SSH を止める
- serve・App Connector・headscale は、使っている人だけ対処すればいい
- 全員共通でやるのは、Tailnet Lock・キーの期限・侵害時は管理画面で端末を削除、の3つ
この記事では攻撃の手順には触れません。「自分は対象か」「何をすればいいか」に絞って書きます。
何が起きたのか
2026年10月25日、Cyberdione Labs の Erica Windisch 氏が「Tailworm」というレポートを公開しました。対象は Tailscale 1.104.2 と headscale 0.29.5 で、10月22日から24日にかけて検証環境で再現を確かめた、と書かれています。速報記事では Cyber Security News の記事(英語)が詳しいです。
押さえておきたい前提が3つあります。
- Tailscale は認めて修正した。公開時点(10月26日)では公式の告知も修正版もなかったが、その後 1.104.4 で直った。詳しくは次の節に書きます
- 結果は検証環境でのもの。実際に悪用された被害は報告されていない。深刻さには異論も出ている
- それでも設定で今すぐ絞れる部分が大きい。修正を待つあいだ、何もしない理由にはならない
ちなみに Tailscale SSH では、2026年7月にも別の問題(TS-2026-009)が 1.98.9 で直っています。こちらは修正済みなので、古い端末が残っていないかだけ見ておけば大丈夫です。
修正版の状況と更新の確かめ方(11月6日時点)
公開から10日たったので、Tailscale と headscale の公式情報を確かめ直しました(2026年11月6日)。
| 日付 | 出たもの | 中身 |
|---|---|---|
| 10月26日 | Security Bulletins TS-2026-014〜017 | Tailscale SSH の Unix ソケット転送(F1・F2・F3)、SSH のメモリ枯渇(F5)、serve の Unix ソケット転送先と HTTP/2 の権限ヘッダー(F7・F8 ほか) |
| 10月28日 | Tailscale 1.104.4 | 上の4件を修正。SSH の転送は root ではなくログインしたユーザーの権限で動くようになった |
| 10月30日 | headscale 0.29.7 | headscale 側の指摘(F6)を修正。Tailscale 側の修正は入らないので、クライアントも 1.104.4 以上にする |
| 11月2日 | Tailscale 1.104.5 | SSH・serve の安定性の修正。この時点の最新 |
CVE 番号はどれにも付いていません。Bulletin の番号(TS-2026-014 など)で追うことになります。
全部が直ったわけではありません。App Connector(F4)は、内部アドレスやメタデータへの踏み台になる部分だけ開発中のコードで塞がれていて、リリース版にはまだ入っていません(Tailworm のサイトの「Upstream response」節による)。App Connector を使っている人は、下の「App Connector(F4)」の対処を続けてください。
更新したかどうかの確かめ方
各端末で次を実行し、1行目が 1.104.4 以上なら修正済みです。Mac の GUI 版は「ぼくの環境で確かめてみた」に書いたアプリ内のパスで実行します。
tailscale version
headscale を運用している場合はサーバーで headscale version を実行し、0.29.7 以上か確かめます。
すぐに更新できない端末は、Bulletin が示す回避策として、tailscaled のサービスの環境変数に TS_SSH_DISABLE_FORWARDING=1 を入れると SSH の転送を止められます。headscale のリリースノートによると、古いクライアントでも効きます。
ぼくの常時起動の Linux サーバーで確かめると、tailscale version は 1.104.5、Tailscale SSH は無効(RunSSH: false)、tailscale lock status は「Tailnet Lock is ENABLED.」でした。記事を書いたときに「要対処」だった Tailnet Lock は有効になっていて、このサーバーは署名済みの端末としてふだんどおり使えています。
修正版が出ても、SSH ルールを組み合わせ単位に絞る・使わない機能を止める、の2つはそのまま続ける価値があります。今回の修正で塞がったのは見つかった穴で、「1台乗っ取られたら広がる」という構造は、ルールが広いままなら残るからです。
被害の広さを決めるのは「SSH ルールの広さ」
レポートでいちばん大事なのは、個々のバグより次の指摘だとぼくは思っています。
Tailscale SSH は、パスワードや鍵ではなく「どの端末からの接続か」だけで、SSH を通すかどうかを決めます。つまり「この端末は信用できる」という前提で動いている。その前提が崩れる(1台が乗っ取られる)と、ルールで許可されたすべての相手に被害が届きます。
研究者の検証でも、広がりを止められた対策は組み合わせ単位の許可(per-pair grants)だけだったそうです。ほかの対策は「気づくのが早くなる」効果はあっても、広がり自体は止めなかった、と。
薬局で例えると、「スタッフ全員がどの金庫も開けられる」状態か、「麻薬金庫は麻薬管理者だけ」状態か、の違いです。前者だと、誰か1人の鍵が盗まれた時点で全部の金庫が危ない。管理薬剤師をやっていたころ、鍵の管理簿をつけるのは正直めんどくさかったけど、あれはこういう事態のためにあるんですよね。
根本の原因は「root のまま動く SSH サーバー」
もうひとつ知っておくと対策を選びやすくなるのが、設計の違いです。
ふつうの SSH サーバー(OpenSSH)は、ログインが終わるとすぐにそのユーザーの権限に落としてから作業します。だから一般ユーザーのセッションから、root 専用の仕組みには触れません。
Tailscale SSH は tailscaled という常駐プログラムの中に SSH サーバーが入っていて、これは root 権限で動いています。レポートによると、SSH の転送機能(ssh -L / ssh -R で Unix ソケットを扱うもの)を root のまま処理してしまうため、一般ユーザーのセッションから root 専用のソケットに届いてしまう、とのことです。
同じ種類の問題は、別の SSH サーバー Dropbear でも CVE-2025-14282 として見つかっていて、2025.89 で「先にユーザー権限へ落とす」形で直っています。なので、Tailscale 側の修正もそれほど大きくはならないはず、というのが研究者の見立てです。
この違いから言えるのは、Tailscale SSH の許可は「root を渡すのとほぼ同じ」と考えて扱うのが安全、ということです。
11件の中身と、それぞれの対処
11件は5つの機能に分かれます。使っていない機能の節は読み飛ばしてOKです。
| # | 機能 | 中身(ざっくり) | レポートの深刻度 | 対象になる人 |
|---|---|---|---|---|
| F1〜F3 | Tailscale SSH | 転送機能が root で動き、root 専用のソケットに触れる | High | SSH で転送を許可している |
| F4 | App Connector(conn25) | 許可されたアプリ以外の宛先にも通れてしまう | High | 実験機能の conn25 を使っている |
| F5 | Tailscale SSH | セッションを使ってメモリを食いつぶせる | High | SSH を許可している |
| F6 | headscale / DERP | 登録処理でメモリを枯渇させられる。悪意あるリレーで端末が落ちる | Medium-High | headscale を公開している |
| F7 | serve | Unix ソケットへの TCP 転送で、管理用の窓口が外から使える | High | serve でソケットへ転送している |
| F8 | serve | 設定後にパスをすり替えると、ソケットのチェックを抜けられる | Medium | 同上(書き込める場所のソケット) |
| F9 | Funnel | Funnel の有効化チェックが手元の設定に頼っている | Medium | Funnel を使える端末 |
| F10 | serve | TS_SERVE_ALLOW_ALL_INTERFACES で Tailnet の外からも見える | 設定の注意 | この変数を設定している |
| F11 | serve | ヘッダーで権限を分けている場合、まれに別の権限が混ざる | Medium〜Low | ヘッダーで認可している |
Tailscale SSH(F1・F2・F3・F5)
対象: Tailscale SSH を有効にした端末がある人。ここがいちばん重いです。
やること
- 使わない端末では止める。別の入り方(OpenSSH やコンソール)があることを先に確かめてから実行します。止めた瞬間に入れなくなる可能性があるので、順番が大事です
sudo tailscale set --ssh=false
- 残す端末は、ポリシーの
sshルールを組み合わせ単位にする。autogroup:memberやタグ全体をdstに並べるのをやめ、「この端末(またはこの人)から、このサーバーへ」と1組ずつ書きます - root や、パスワードなしで sudo できるアカウントを
usersに入れない。ただしレポートの指摘は一般ユーザーのセッションから成立するので、これは補助的な対策です - 転送を禁止する。レポートは「SaaS 版ではルールごとに転送を拒否できる」としています。ただ、ぼくが公式のポリシーファイルのリファレンスを確認した範囲(2026年10月26日)では、
sshルールに書ける項目はaction/src/dst/users/checkPeriod/acceptEnv/srcPostureだけで、転送を止める項目は見つかりませんでした。なので、転送を確実に止めたいなら Tailscale SSH をやめて、Tailnet 越しに OpenSSH を使うのが現実的だと思います。OpenSSH ならsshd_configに次の1行で転送をまとめて止められます
DisableForwarding yes
この場合はネットワークの ACL(grants)で、22番ポートへの通信も組み合わせ単位で許可してください。
F5(メモリの食いつぶし)だけは、Tailscale 側でできる回避策がレポートでも見つかっていません。上流のライブラリ(gliderlabs/ssh)の修正待ちです。SSH を許可する相手を絞ることが、そのまま F5 の影響を小さくします。
check モードを使っている人へ
action: "check"(接続前にブラウザで再認証させる設定)を、強い守りだと思って使っている人もいると思います。レポートはここにも注意を出しています。
- check モードが確認するのはセッションを始めるときだけ。始まったセッションの中の転送は制限しない
- SaaS 版では、1回の承認がほかの check 対象すべてに有効になる(期間は
checkPeriod、既定は12時間) - 自分で開いた覚えのない認証の画面が出たら、それ自体をインシデントとして扱う
なので、大事なサーバー向けのルールは checkPeriod を数分か "always" にしておくのがおすすめです。
tailscale serve と Funnel(F7〜F11)
対象: tailscale serve や Funnel を使っている人。
| # | 確認すること | 対処 |
|---|---|---|
| F7 | tailscale serve status に、unix: で始まる転送先がないか | あれば消す。特に tailscaled.sock を指しているものは必ず消す |
| F8 | Unix ソケットの転送先が、誰でも書き込めるディレクトリにないか | localhost の TCP ポートに切り替えるか、root だけが書ける場所に置く |
| F9 | tailscale funnel status で、意図しない Funnel が有効になっていないか | 使わないなら止める。serve の設定を変えられる人(operator)を最小限にする |
| F10 | 環境変数 TS_SERVE_ALLOW_ALL_INTERFACES を設定していないか | 必要がなければ外す(Kubernetes operator の実験的な機能が設定することがある) |
| F11 | serve の複数のパスで、Tailscale-App-Capabilities ヘッダーを使って権限を分けていないか | 権限の違うアプリは別のポートやホスト名に分ける(ぼくの判断。レポートの提案は Tailscale 側の修正) |
ぼくが見た限り、serve を http://localhost:3000 のような TCP のローカルポートに向けているだけなら F7・F8 には当たりません。ぼくの使い方もこれでした。
App Connector(F4)
対象: 実験機能の conn25(新しい App Connector の仕組み)を使っている人。従来の App Connector だけなら対象外です。
レポートによると、アプリの利用を許可されたユーザーが、そのアプリ以外の宛先にもコネクタ経由で通れてしまいます。クラウドの認証情報が取れるメタデータサービスや、Kubernetes のクラスタ内のサービスまで届く、とのこと。
やること
- 使っていない端末から、コネクタの権限を外す
- コネクタのホストで、ファイアウォールで宛先を許可リストにする。特に
169.254.0.0/16(メタデータ)は無条件で止める - Kubernetes では、コネクタの namespace に「既定で外向き通信を拒否」する NetworkPolicy を入れる
- 1台のコネクタ(同じ外向き IP)に複数のアプリを相乗りさせない
headscale(F6)
対象: Tailscale の代わりに headscale を自分で運用している人。
- systemd の
MemoryMaxでメモリの上限を決め、落ちても自動で再起動するようにする - 登録の窓口の前にレート制限つきのリバースプロキシを置く
- インターネットに丸出しにせず、管理用のネットワークや VPN からだけ届くようにする
- headscale 0.29.5 では SSH の転送を止められないので、SSH の許可はすべて root を渡すのと同じとみなし、許可そのものを減らす
- 端末が使うリレー(DERP)は、自分が管理しているか信頼できるものだけにする
全員共通でやること
ここまでの機能を使っていなくても、次の3つはやっておく価値があります。どれも「乗っ取られたあとに被害を長引かせない」ための対策です。
1. Tailnet Lock を有効にする
Tailnet Lock を有効にすると、信頼済みの端末が署名しない限り、新しい端末は参加できません。レポートでも、Lock が無効な初期設定だと被害が大きくなると書かれています。
2. キーの期限をつける
タグをつけた端末は、初期設定でキーの期限が無効になっています。サーバーにも期限をつけておけば、盗まれた鍵がいつまでも使える状態を避けられます。対応している端末なら、TPM や Secure Enclave に鍵を置く設定も有効です。
3. 侵害を疑ったら、管理画面で端末を削除する
ここは誤解しやすいところです。端末の鍵はファイルとして保存されているので、root を取られたらコピーされたと考える必要があります。OS を入れ直しても、コピーされた鍵は生きたまま。止められるのは管理画面からの削除(か期限切れ)だけです。
削除したら、その端末から使えた認証キーや資格情報も作り直します。Tailnet Lock の署名に使っていた端末なら、Lock の鍵も入れ替えます。最後に、ポリシーの変更履歴に覚えのない変更がないかも見ておきましょう。
ちなみに、Hugging Face の侵害でも、盗まれた Tailscale の認証情報で181台が登録されたと Tailscale が説明しています(こちらは脆弱性ではない)。コードの問題と同じくらい、鍵の扱いが大事ということですね。
検知の仕組みを入れられるなら
Linux のサーバーを多く抱えている組織なら、レポートが挙げている次の監視も検討してください。
- auditd で、
/tmp・ホーム・/run/userとtailscaled自身のソケットの作成・削除・権限変更を記録する - 認証キーの発行と利用、見たことのない鍵での端末の参加を通知する
- headscale のメモリ使用量と登録の遅延を監視する
ただし、検知は「気づくのが早くなる」だけで、広がる速さ自体は変えません。
対策の効き目を並べると
ここまでの対策を、効き目の大きい順に積み重ねるとこうなります。上の層で止めきれなかったものを、下の層が受け止める形です。
一番上の「組み合わせごとに許可」が、唯一広がりそのものを止める層です。ほかの層は、それをすり抜けたときの保険だと考えると優先順位がつけやすいです。
ぼくの環境で確かめてみた
記事を書く前に、自分の Tailnet を一通り点検しました。手元は Mac mini(Tailscale 1.102.4)が中心で、ほかに MacBook、Windows、iPhone、Android、Linux が数台つながっています。
まずつまずいたのが、Mac で tailscale コマンドが見つからないこと。App Store / GUI 版を入れている場合、CLI はアプリの中にあります。
/Applications/Tailscale.app/Contents/MacOS/Tailscale version
点検に使ったコマンドはこれだけです。どれも状態を表示するだけなので、安心して実行できます。
# この端末で Tailscale SSH と App Connector が有効か
tailscale debug prefs | jq '{RunSSH, AppConnector}'
# SSH のホスト鍵を公開している端末(Tailscale SSH が有効な端末の目安)
tailscale status --json | jq -r '.Peer[] | select((.sshHostKeys // []) | length > 0) | .HostName'
# serve と Funnel の設定
tailscale serve status
tailscale funnel status
# Tailnet Lock の状態
tailscale lock status
結果はこんな感じでした。
| 項目 | ぼくの環境 | 判定 |
|---|---|---|
| Mac mini の Tailscale SSH | 無効 | 対象外 |
| serve | localhost の TCP ポートに転送しているだけ | F7・F8 は対象外 |
| Funnel・App Connector | どちらも使っていない | 対象外 |
| Linux 2台の Tailscale SSH | 有効 | 要対処 |
| Tailnet Lock | 無効 | 要対処 |
正直、Linux の2台で Tailscale SSH を有効にしていたことは完全に忘れていました。以前、開発用に立てたときにオンにして、そのまま。しかもぼくは Tailnet の管理者なのに、Tailnet Lock も有効にしていなかった。
「自分は大丈夫でしょ」と思っていたのに、ふたを開けたら2つ引っかかったわけです。点検してよかった…。2台はどちらもオフラインだったので、次に起動したときに tailscale set --ssh=false で止めて、Tailnet Lock を有効にする予定です。
自分の環境でやることを決める
最後に、ここまでの内容を判定フローにまとめておきます。上から順に答えていけば、自分がやることにたどり着きます。
評価が割れていることも書いておく
公平のために書いておくと、このレポートには「深刻さを大きく見せすぎだ」という声もあります。結果はあくまで研究者の検証環境のもので、実際の被害は報告されていません。また、ほとんどの項目は「すでに1台が乗っ取られている」ことが前提です。
ただ、ぼくの結論は変わりません。SSH ルールを組み合わせ単位にする、使わない機能を止める、Tailnet Lock を入れる。この3つは修正版が出たあとも続ける価値のある、基本の守りだからです。
Tailscale からの公式な情報は Security Bulletins に出ます。修正版(1.104.4)はもう出ているので、全端末を更新しましょう。Tailscale SSH 自体の仕様は公式ドキュメントにあります。
まとめ
- Tailworm は Tailscale と headscale の問題11件をまとめたレポート。Tailscale 1.104.4・headscale 0.29.7 で修正された(App Connector は一部のみ)。全端末を更新する
- いちばん重いのは Tailscale SSH。SSH の許可は root を渡すのと同じと考え、組み合わせ単位に絞る。使わない端末では止める
- serve(Unix ソケットへの転送)・App Connector(conn25)・headscale は、使っている人だけ対処する
- 全員共通で、Tailnet Lock・キーの期限・侵害時は管理画面で削除
Tailscale は、ぼくがスマホから自宅の PC に入って開発するのに欠かせない道具です(構築の手順は「TailscaleでClaude CodeにSSH接続する方法」に書きました)。便利な道具だからこそ、「つながる範囲」をときどき棚卸しするのが大事だなと改めて思いました。
続報が出たら、この記事も更新します。気になる方は X(@hagakun_yakuzai) をフォローしてもらえるとうれしいです🙌
急に朝晩が冷えてきましたね。サーバーの棚卸しついでに、衣替えもしないと…。