← ブログに戻る
9 novembre 2026 · 3 min で読了

Semaphore UI と HFS:私たちが報告した2つの認可の欠陥

GHSA-ffp6-w57q-758q と GHSA-c3w7-ff56-j345:Semaphore UI では Manager が別プロジェクトの Vault を自分のプロジェクトへ移すことができ、HFS では匿名の訪問者が、別の訪問者がアップロードしたばかりのファイルを置き換えることができました。私たちが見つけた内容と、導入すべきバージョンを解説します。

サイバーセキュリティSemaphore UIHFSAnsibleWebDAV脆弱性開示
2つの脆弱性の図解:Semaphore UI ではプロジェクト A の Manager がプロジェクト B の Vault を移し、HFS では2人目の匿名訪問者が、別の訪問者がアップロードしたばかりのファイルを置き換える

2026年11月9日、1時間も経たないうちに、まったく異なる2つのオープンソースプロジェクトが、クレジットに同じ名前を載せたセキュリティアドバイザリを公開しました。1つは Semaphore UI。多くのチームが自社サーバーで Ansible や Terraform を実行するのに使う Web インターフェースです。もう1つは HFS。2003年から、自分のコンピューターのフォルダーをブラウザだけで共有できるようにしてきたファイルサーバーです。Semaphore では、あるプロジェクトのユーザーが、別のプロジェクトのテンプレートの Vault 設定を奪うことができました。HFS では、削除が禁止されたフォルダーで、匿名の訪問者が、別の匿名訪問者がアップロードしたばかりのファイルを置き換えることができました。

対象となるのはアドバイザリ GHSA-ffp6-w57q-758q(Semaphore UI 2.19.20 で修正)と GHSA-c3w7-ff56-j345(HFS 3.4.1 で修正)です。報告したのは私たちで、どちらも Webcracy の共同創業者でエシカルハッカーの Liam Giannini(GitHub の Liam-G)が発見しました。アドバイザリと修正版を同じ日に公開してくれた Semaphore のメンテナーと、HFS の作者 Massimo Melina に感謝します。

2つの欠陥はまったく別物に見えますが、根は同じです。どちらのプログラムも身元を確認していました。ただ、確認していたのが間違った身元だったのです。

Webcracy とサイバーセキュリティ

Webcracy はウェブサイトやアプリケーションの開発に加えて、サイバーセキュリティのあらゆる領域に取り組んでいます。ネットワークとサーバーを守り、当社のSOCで昼夜監視し、インシデントが起きれば対応し、監査、コンサルティング、システムのハードニングを行い、ペネトレーションテストとコードレビューで防御を試します。私たちや顧客が使うオープンソースソフトウェアの調査は、その仕事の一部です。Liam は攻撃者と同じ方法で脆弱性を探しますが、目的はそれを塞ぐことです。見つけた問題は非公開でメンテナーに報告し、修正が公開されてから初めて公表します。ProjectSend、exarch、FreeScout と同じ 責任ある開示 の手順です。

Semaphore UI:プロジェクトをまたいで移動した Vault

Semaphore UI が重要な理由

Semaphore UI は、Ansible、Terraform、OpenTofu、Terragrunt、Pulumi、PowerShell をコマンドラインを使わずに実行するための Web インターフェースと API です。まだ Ansible Semaphore と呼ばれていた2014年から存在し、Go で書かれ、MIT ライセンスで公開されています。GitHub では 14,400 以上のスター、1,300 以上のフォーク、180 人以上のコントリビューターを持ち、公式 Docker イメージ semaphoreui/semaphore は 860 万回以上ダウンロードされています。旧イメージ ansiblesemaphore/semaphore の約 60 万回もこれに加わります。プロジェクトのサイトは 10 万件以上のインストールをうたっています。開発元の数字ですが、桁としては他のデータと整合しています。オープンソース版のほかに、有料の Pro 版と Enterprise 版があります。

Ansible の世界では、AWX や Red Hat の Ansible Automation Platform の軽量な代替です。単一のバイナリで、SQLite データベースでも起動でき、AWX のように Kubernetes クラスターを必要としません。そのため、新たなインフラを構築せずに Ansible の UI がほしい人によく選ばれています。

そして、ここでは認可の欠陥が他より重くなります。この種のツールには SSH 鍵、クラウドの認証情報、暗号化された秘密情報を解錠するパスワードが保存されており、インフラ全体へコマンドが送られる起点です。だからこそプロジェクトに分けられ、同じインストールが複数のチームや複数の顧客に使われることも少なくありません。プロジェクト間の境界は、実質的に「誰が何に触れられるか」の境界なのです。

テンプレートの Vault とは

Semaphore の テンプレート は、実行するジョブを表します。どのプレイブックを、どのインベントリに対して、どの変数で実行するか。多くのプレイブックには Ansible Vault で暗号化された秘密情報が含まれており、復号にはパスワードが必要です。テンプレートは1つ以上の Vault 紐付け によって、その取得元を指定します。プロジェクトに保存された鍵か、外部システムから取得するスクリプトです。データベースでは、各紐付けは project__template_vault テーブルの1行で、固有の数値 ID と、所属するプロジェクトとテンプレートを持ちます。

チェックが欠けていた場所

テンプレートは POST /api/project/{project_id}/templates で作成します。ミドルウェアは、ユーザーが URL のプロジェクトのメンバーであり、そのリソースを管理できること(Manager ロールで許可される)を正しく確認していました。新しいテンプレートはそのプロジェクトに割り当てられますが、vaults リストはクライアントが送ったままデータベースに届いていました。

欠陥は UpdateTemplateVaults 関数にありました。ID がゼロでない各項目について、既存の紐付けの更新だとみなし、次の SQL を実行していたのです。

UPDATE project__template_vault
SET project_id=?, template_id=?, vault_key_id=?, name=?, type=?, script=?
WHERE id=?

行は id だけで選ばれ、どのプロジェクトに属するかは確認されず、しかも更新でまさに project_id と template_id が書き換えられ、攻撃者の新しいテンプレートのものになりました。余分な紐付けの削除はプロジェクトで絞り込まれていましたが、その時点で行はすでに移動していました。

つまり攻撃者は、自分のプロジェクトでテンプレートを作成し、vaults リストに被害プロジェクトの紐付けの ID を入れるだけでよかったのです。種類を script にすると鍵のフィールドが空になるため、相手プロジェクトについて他の情報は必要ありません。ID はデータベースが順番に割り当てる数字で、秘密ではありません。チェックは URL のプロジェクトを見ていましたが、変更対象はリクエスト本文の番号で選ばれていました。CWE カタログではこれを CWE-639(ユーザーが制御するキーによる認可のバイパス)と CWE-863(不正な認可)と呼びます。

深刻度

リクエストの後、被害プロジェクトのテンプレートは Vault 紐付けを失い、攻撃者のテンプレートがそれを持つことになります。最も起こりやすい結果は、秘密情報の復号が必要な実行が、誰かが設定を作り直すまで失敗することです。テストではこれを測定していません。あり得る結果であって、実証されたものではありません。

見つから なかった ことも同じく正確に述べます。秘密情報の読み取り、被害者の鍵の使用、コード実行はいずれもありません。また、攻撃者は少なくとも1つのプロジェクトで Manager ロールまたは同等の権限を必要とします。そのため深刻度は「中程度」です。それでも、インフラを指揮するツールにおける「中程度」とは、ユーザーがまったくロールを持たないプロジェクトを変更でき、他のチームや顧客のプロジェクトを管理する人がそれに気づけなかったということです。

検証方法

この問題は、Semaphore UI 2.19.18(コミット b621d14)のコードを読み、vaults リストをルーターから SQL クエリまで追うことで見つかりました。確認のため、Liam は Go で回帰テストを書きました。リリースのインメモリ SQLite ストアと元のコンポーネント(プロジェクトのミドルウェア、権限チェック、テンプレート作成、SQL レイヤー)を使うものです。テストは A と B の2つのプロジェクトを作り、ユーザーを A だけの Manager にし、B に Vault 付きのテンプレートを作成したうえで、B の紐付けの ID を含めて A にテンプレートを作成するよう要求します。API は 201 を返し、B のテンプレートの紐付けは1件から0件になり、A の新しいテンプレートには B の元の紐付けが含まれていました。

同じクエリは少なくとも 2.11 以降の Semaphore のコードに存在しています。アドバイザリが示しているのは私たちが検証した 2.19.18 だけで、それ以前のどのバージョンが同じように悪用できるかは確定していません。悪用できると考えておくのが安全です。

2.19.20 での修正

バージョン 2.19.20 に、プルリクエスト #4414 のコミット 9445ee9 として修正が含まれています。更新はもう project_id と template_id に触れず、行が本当に認可されたプロジェクトとテンプレートに属している場合にだけ見つけます。

UPDATE project__template_vault
SET vault_key_id=?, name=?, type=?, script=?
WHERE id=? AND project_id=? AND template_id=?

別のプロジェクトの ID は、もはや何の効果も持ちません。メンテナーはアドバイザリのシナリオを再現するテスト TestManagerCannotMoveForeignProjectVault も追加しました。私たちは報告の中で、更新が1行も一致しない場合にリクエストを拒否すること、テンプレートと紐付けを1つのトランザクションで作成することも提案していました。公開された修正で攻撃経路は塞がれており、その他の対策はメンテナーの判断に委ねられています。

Semaphore UI を使っている場合にすべきこと

少なくとも 2.19.20 に、できれば数分後に公開された 2.19.21 にアップデートしてください。そのリリースノートによると、ユーザーが現在のパスワードを知らなくても API で自分のパスワードを変更できたという別の問題も修正されています。Docker では latest ではなく明示的なバージョンを指定してください。

アップデート後は、Ansible Vault を使うテンプレートが紐付けを保っているか確認しましょう。明確な理由なく Vault を失ったテンプレートがあれば、その原因のひとつがわかったことになります。また、誰がどのプロジェクトで Manager ロールを持っているかも見直してください。サービス提供者の異なる顧客同士のように、2つのユーザーグループの分離が本当に重要な場合、単一インストール内のプロジェクトは有用ではあっても絶対的な境界ではありません。データベースを分けた別々のインスタンスにすれば、次の認可の誤りによる被害を抑えられます。

HFS:別の匿名ユーザーが置き換えられた、アップロードしたばかりのファイル

HFS が重要な理由

HFS(HTTP File Server)は、IT の仕事に数年携わった人ならほぼ確実に出会ったことのあるプログラムです。オンラインでは rejetto として知られる Massimo Melina が2000年代初めから開発しており、自分のコンピューターで起動して共有するフォルダーを選べば、アドレスを知っている人は誰でもブラウザでファイルをダウンロード・アップロードできます。間にクラウドサービスは入りません。SourceForge では2003年以降 97 万回以上ダウンロードされており、作者のサイトからのダウンロードはこれに含まれていません。TypeScript と Node.js で書き直され、GPL-3.0 で公開されている HFS 3 は、Windows、Linux、macOS、FreeBSD、Android で動作します。GitHub では約 4,000 のスターと 370 以上のフォークがあり、リリースパッケージは 50 万回以上、Docker イメージ rejetto/hfs は 11 万 6 千回以上、npm パッケージは過去1年で約 4 万 4 千回ダウンロードされています。

ローカルネットワークでのファイルの受け渡しや、顧客や協力者から書類を受け取る用途に向いています。そうした場面では、匿名アップロードを許可しつつ削除は禁止するフォルダーはごく普通の設定です。誰でもファイルを置けるが、誰も持ち去れない、というわけです。

WebDAV に与えられた10秒間

2026年4月に公開されたバージョン 3.1.0 から、HFS は WebDAV に対応しています。共有フォルダーを Windows のエクスプローラーや Mac の Finder でネットワークドライブとして接続できるプロトコルです。一部の WebDAV クライアントは独特の動きをします。たとえば Finder は、まず空のファイルを作成し、すぐに本来の内容で上書きします。しかしファイルの上書きには削除権限が必要で、「アップロードのみ」のフォルダーではその権限がありません。

こうしたクライアントを壊さないために、HFS は認識済みの WebDAV クライアントでファイルをアップロードしたばかりの人に、削除権限がなくても10秒間はそのファイルを置き換えられるようにしていました。合理的な妥協です。問題は、HFS が「アップロードしたばかりの人」を誰だと判断していたかです。

匿名ユーザーは全員同じ名前

この一時的な許可は、ファイルのパスとユーザー名という2つの要素からなるキーで保存されていました。登録ユーザーならこれで機能し、異なる2つのアカウントが互いの許可を使えないことを確認する自動テストまでありました。しかしログインしていない人について、HFS は名前として空文字列を返します。匿名の訪問者は全員同じ名前、つまり同じキーを持っていたのです。

そのため2人目の匿名訪問者は、1人目の Cookie や認証情報なしに、10秒以内に同じパスへ PUT リクエストを送ることができました。条件は、ユーザーエージェント に WebDAV という単語を含めることだけです。HFS は許可を見つけると、新しいアップロードを処理する前に既存のファイルを削除し、can_delete のチェックも、匿名アップロードをそれを行ったセッションに結び付ける保護も迂回しました。新しいアップロードが成功すればファイルは置き換えられ、失敗したり中断されたりしても、元のファイルは削除されたままでした。既定で有効な force_webdav_login オプションもこのリクエストを止めませんでした。WebDAV 固有のヘッダーを持たない単純な PUT は、WebDAV の認証リクエストとして扱われなかったからです。こちらも CWE カタログでは CWE-863(不正な認可)にあたります。

深刻度

条件は限られています。匿名アップロードが許可され削除が禁止されたフォルダー、WebDAV クライアントでアップロードされたばかりのファイル、そのパスの把握、そして10秒以内の2回目のリクエストが必要です。古いファイルには届きません。深刻度は「中程度」です。

しかしその時間枠の中では、影響は具体的です。公開されたばかりで、すでにアドレスで他の人と共有されているかもしれないファイルを、誰でも同じアドレスのまま別の内容に置き換えられました。受け取り用フォルダーであれば、受け取った書類が送り主の送ったものではないかもしれない、ということです。

検証方法

Liam は HFS 3.3.4(コミット bb6f718)のコードで処理の流れを追い、同じコードがメインブランチにも残っていることを確認しました。そのうえでサーバーをビルドし、ネットワークにアクセスできない Docker コンテナで起動しました。uploads フォルダーはアップロード可、削除不可に設定しています。1つ目の匿名セッションが、Windows の WebDAV クライアントのユーザーエージェントで first という内容のファイルをアップロードしました。Cookie を持たない2つ目のセッションがそれを削除しようとすると、HFS は正しく 403 を返しました。続いて同じ2つ目のセッションが同じパスに second という内容の PUT を送ると、HFS は 200 を返し、元のアドレスのファイルは second になっていました。

2つのリクエストは同じ IP アドレスから送られましたが、キーにはセッションも IP も含まれていません。コードからは、異なるアドレスからでも結果は同じになると考えられますが、そのケースは個別にはテストしていません。アドバイザリは 3.1.0 から 3.4.0 までのすべてのバージョンを影響ありとしています。

3.4.1 での修正

11月9日に公開されたバージョン 3.4.1 のリリースノートには、コミット 9a33df2 による変更が1つだけ記載されています。一時的な許可は、ユーザー名、または匿名訪問者の場合はそのセッション ID に結び付けられるようになりました。どちらもなければ、許可は与えられません。これは私たちが提案した修正そのものです。新しい自動テストは両側を確認します。別の匿名セッションは 403 を受け取り、アップロードした本人は Finder と同じように引き続きファイルを上書きできます。

HFS を使っている場合にすべきこと

3.4.1 以降にアップデートしてください。HFS にはサービスとして動作している場合にも使える自動アップデート機能があるので、通常は短時間で済みます。何らかの理由ですぐにアップデートできず、匿名アップロードのフォルダーがある場合は、少なくとも修正を導入するまでは、アップロードにアカウントを必須にすることを検討してください。

より一般的に言えば、匿名アップロードを許可するフォルダーは、定義上開いた扉です。多くの場面で意味がありますが、他の人に公開するためではなくファイルを受け取るために使い、中身を定期的に確認するのがよいでしょう。

同じ誤りが2回

Semaphore は、ユーザーが URL のプロジェクトで 作業できるかを確認したうえで、リクエスト内の番号で選ばれたオブジェクトを変更していました。HFS は、ファイルが 同じユーザーによって アップロードされたかを確認していましたが、使っていたのはすべての匿名訪問者で同一の名前でした。どちらの場合もチェックは存在し、丁寧に書かれ、一方はテストでカバーまでされていました。欠けていたのは正しい問いです。「いま確認している身元は、これから操作する人物とオブジェクトのものなのか」。

こうした誤りは、アプリケーションを普通に使っていても見えません。値をリクエストから使われる場所まで追い、そのたびに「この値は誰が決めたのか」と問うことで見えてきます。それが私たちの仕事の一部です。

なぜオープンソースソフトウェアを調査するのか

Semaphore や HFS のようなツールがあるからこそ、小さなチームでも何十台ものサーバーを管理したり、クラウドサービスに頼らずにファイルをやり取りしたりできます。オープンソースで、無料で、導入も簡単です。しかしアプリケーションが広く使われるほど、内部のチェックは重要になります。私たちが使い、勧めているプロジェクトのコードを読み、見つけたことを報告するのは、これらのプロジェクトに何かを還元し、顧客のために何を導入しているのかを知るための私たちのやり方です。

自動化ツール、ファイルサーバー、あるいは複数のユーザーとロールを持つアプリケーションを使っていて、権限が本当に機能しているか知りたい場合は、ぜひご相談ください。私たちのサイバーセキュリティの仕事には、ネットワークの防御と監視、インシデント対応、監査、ハードニング、ペネトレーションテストが含まれ、いつもここから始まります。コードと設定を読み、どこにチェックが欠けているかを把握し、何を検証して何を検証していないかを正確にお伝えします。

御社のセキュリティについてご相談ください

プロジェクトをお持ちですか?

オーダーメイドのデジタルソリューションで、御社のビジネスをどうサポートできるか、ご相談ください。

お問い合わせ