世界を動かす技術を、日本語で。

Vetはcurl | bashパターンの安全ネットです

概要

vet は、curl | bashパターンのリスクを軽減するコマンドラインツール。 リモートスクリプトの 差分確認lint解析明示的な承認 を経て実行。 Homebrew や手動インストールに対応し、安全性を重視。 Bash 4+ 必須で、セキュリティ重視の設計思想。 貢献方法 やライセンス情報も明記。

vetとは何か

  • vet は、curl | bashパターンの 危険性 を解消するためのCLIツール
  • リモートスクリプトを 安全にレビュー・実行 するワークフローを提供
  • スクリプトの変更点表示lint解析ユーザー承認 のプロセスを自動化
  • 「Don't just run it, vet it.」 がコンセプト

背景:curl | bashパターンの問題点

  • curl -sSL https://example.com/install.sh | bash のような ワンライナー実行 は便利だが危険
  • 悪意あるスクリプトサーバーの侵害ネットワークエラー による部分的なスクリプト実行リスク
  • 信頼性の担保が困難 であることが課題

vetによる解決策

  • Fetch :リモートスクリプトを一時的な場所にダウンロード
  • Diff & Review :前回実行時からの 差分表示 による安全確認
  • Lintshellcheck がインストールされていれば自動解析(バグや悪意の検出)
  • Confirm明示的な承認 なしにはスクリプトを実行しないインタラクティブ設計
  • 新しい安全な実行方法 :vet https://example.com/install.sh

インストール方法

  • Homebrew(macOS/Linux)推奨
    • 公式リポジトリをtap:brew tap vet-run/vet
    • インストール:brew install vet-run
    • Homebrew内の他ツールとの 競合回避 のため、formula名はvet-run
  • 手動インストール(セキュリティ重視)
    • スクリプトをダウンロードし、内容を確認後に実行
      • 公式ドメイン:curl -o install_vet.sh https://getvet.sh/install.sh
      • GitHubリリース:curl -L -o install_vet.sh https://github.com/vet-run/vet/releases/latest/download/install.sh
    • lessやエディタで 内容確認 後、bash install_vet.shで実行
    • 自動化された安全プロセス の体験

非推奨:curl-to-bashパターン

  • curl -sL https://getvet.sh/install.sh | bash のような 直接実行 は推奨しない
  • vetで安全性を確保 することが目的

基本的な使い方

  • 基本コマンド :vet <URL>
  • 実例 :vet https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh
  • 引数渡し :vet https://example.com/setup.sh --user myuser --version latest
  • 非対話モード (自動化環境向け):vet --force https://my-trusted-internal-script.sh

オプション一覧

  • -f, --force: 全てのプロンプトをスキップし即実行 (注意して使用)
  • -h, --help: ヘルプメッセージ 表示

プロジェクトの思想・技術的決定

  • Bash 4+必須 :安全性・堅牢性・可読性重視のため、POSIX sh互換よりも 最新bash機能 を優先
  • Alpine Linux等の最小環境 では、bashの明示的なインストールが必要:apk add --no-cache bash

コントリビューション方法

  • バグ報告や新機能提案 はIssueで受付
  • Pull Request手順
    • リポジトリを Fork
    • 新機能ブランチ作成:git checkout -b feature/my-amazing-feature
    • 変更を加える
    • テスト実行:bats tests/
    • コミット:git commit -am 'Add some amazing feature'
    • プッシュ:git push origin feature/my-amazing-feature
    • Pull Request作成

謝辞・ライセンス

  • 貢献者一覧 はContributorsファイルで公開
  • MITライセンス で提供、詳細はLICENSEファイル参照

Hackerたちの意見

素晴らしいアイデアだね。特に「curl | bash」がサーバーで検出される可能性があるからね。[1](もしサーバーが侵害されたら、実行した人だけに悪意のあるコンテンツを提供することができる)[1] https://web.archive.org/web/20250622061208/http://idontplayd...

そうだけど、サーバーが侵害されてたら、インストールしてるバイナリに直接マルウェアを注入される可能性もあるよね?結局のところ、別の信頼できるソースでハッシュを確認できるパッケージを直接ダウンロードしてるときだけ安全だと思う。その他は、ダウンロードしてるサーバーの思い通りになっちゃうよ。

これは理論上の問題で、実際には全く影響がないよね。

curl|bashに対する俺の問題は、スクリプトが悪意のあるものである可能性じゃないんだ。インストールしているソフトウェア自体も同じように悪意があるかもしれないからね。俺が気にしてるのは、スクリプトが無能に書かれているか、俺みたいなユーザーを考慮していないかもしれないってこと。だから、インストールが壊れた方法で行われたり、脆弱だったり、非標準的な方法で行われる可能性があるんだ。俺は、単一のバイナリをダウンロードして、自分が知っている場所にインストールする方がずっといい。

手動で読んでみると、すごくよく書かれたスクリプトも見たことがあるよ。そういうスクリプトは、インストール先や機能、Python環境とのオプション統合などを変更できるんだ。俺は、こういう方法でダウンロードしたスクリプトは、実行する前にざっと目を通すようにしてる。理由はいろいろあって、「これは悪意があるのか?」から「使いたいオプションがあるのに教えてくれないのか?」まで幅広い。特に気になるのは、俺のディストリビューションのパッケージマネージャーと統合する設定をしているのか、それともユーザーのファイルシステムのどこかに適当に放り込むのか、もしそうならどこに置くのかを知りたいんだ。

curl | bashがLinuxエコシステムで広まった理由の多くは、「単一のバイナリがそのまま動く」アプローチが実際には実現不可能だからなんだ(1)。さまざまなディストリビューションが十分な標準に従っていないからね。WindowsやMacOSは、単一のベンダーなので、アプリケーションを既存のエコシステムに追加するためのインストールツールが比較的簡単にできるように、十分に標準化された構成を持っている。どのオーディオサブシステムをインストールしたか、systemdの権力争いでどの側にいるか、どの人気のデスクトップ環境をインストールしたか、または/devディレクトリが完全に埋まっているかどうかを心配する必要がない。MacやWindowsでは、これらの質問に対する答えは一つだから、ランダムなバイナリをそこに放り込むだけでうまくいく。Linuxエコシステムのジャングルを考えると、そのbashスクリプトは、あなたのマシンでツールを立ち上げるために多くの互換性確認や代替選択を行っているんだ。「バイナリの塊を渡してもらって、彼らが提供したマニフェストに基づいて接続する方がいい」と言いたいなら、ほとんどの人はそのレベルの設定をしたくない。二つのOSエコシステムがうまく動いている中で、彼らは自分のLinuxディストリビューションも同じようにうまく動いてほしいと思っているんだ。(1)伝統的には実現可能。snapやflatpakのようなプロジェクトは、Dockerの成功からヒントを得て、実行可能ファイルとその依存関係をバンドルして、特定の「ホーム」ディストリビューションが何であるかを心配する必要がなくなるようにしている。ほとんどの場合、必要なオーディオやシステム、その他の依存関係を持っているからね。ただし、これらの冗長な技術スタックがディスクやメモリに常駐し、同じ親イメージの子パッケージでない限り統合できないというコストがかかる。

そうそう!こういうのに求めてるのは、インストールプロセスをサンドボックス化して、アンインストールが確実にできるようにすることなんだよね。

俺がこれに対して抱いてる問題は、安全じゃない行動を助長することだよ。初心者がそのパターンを何回繰り返すんだろう?それで、どっかのバカがDiscordでcurl|bashを投げ込んでくるっていう。IRCはこういうトリックの戦場だったし、Homebrewみたいな正当なプロジェクトがユーザーに、環境にランダムなコードを直接実行するのが普通だって教えてるのが気になる。

これが俺がずっと抱えてる不満なんだよね。特に、自動更新がないことと、強制的に不変の単調な公開バージョン履歴がないこと。これが原因で、各プログラムが独自の非標準な自己更新ロジックを実装する羽目になって、システムパッケージマネージャーに頼らなくなっちゃうんだよね。 https://docs.sweeting.me/s/against-curl-sh

まさにその通りだね。何をするか全然わからないよね。単にPythonとvirtualenvがあるかチェックして、全部を一つのディレクトリにインストールするだけなのか?それとも、信頼できるリモートソフトウェアリポジトリを追加してシステムを乗っ取るのか?新しいユーザーを作ったり、ネットワークポートを開いたり、必要な古いJavaのバージョンをインストールしたり、システムのバイナリを「より良い」ものに置き換えたり、Dockerをインストールしたりするのか?オペレーティングシステムには、エンドユーザーにソフトウェアを配布するための標準的な方法があるんだから、それを使おうよ!確かに、DebianパッケージやRPMをビルドできるようにするために一手間かかるかもしれないけど、少なくともソフトウェアが他のものとちゃんと共存できるからね。それに、もしあなたのソフトウェアがそんなにプライドが高くて独自のOSイメージが必要なら、Dockerコンテナにパッケージ化しちゃえばいいんだよ。でも本当に、車輪を再発明しようとするのはやめてくれ。

俺は「yy030」っていう小さなプログラムを、スクリプトやインタラクティブに一日に何度も使ってる。これは標準入力からURLをフィルタリングするんだ。ちょっと「urlview」に似てるけど、もっとシンプルな正規表現を使ってて、速いんだよね。「curl|bash」で配布されてるサードパーティのソフトウェアは使ってないし、実際にはcurlやbashも使わないけど、もし使ったらyy030を使ってinstall.shからURLを抽出するかも。例えば、こんな感じでね:curl https://example.com/install.sh|yy030とか、curl https://example.com/install.sh > install.sh yy030。別のフィルター「yy073」は、URLのリストをシンプルなウェブページに変えるんだ。例えば、curl https://example.com/install.sh|yy030|yy073 > 1.htm。そしたら、1.htmをHTMLリーダーで開いて、好きなファイルをダウンロードしたり、処理したりできるんだ。ちょっと「urlview」みたいにね。「fzf」とかは使ってないよ。yy030とyy073は50k未満の小さな静的バイナリで、コンパイルも1秒くらいで終わる。標準入力で受け取ったURLをダウンロードする小さなスクリプトもあるんだ。例えば、install.shから3番目のURLを1.tgzにダウンロードするには、yy030 "ftp"はクライアントがtnftpを意味して、"0"は標準入力を指すんだ。

moreutilsのvipeも使えるよ:curl -sSL https://example.com/install.sh | vipe | sh これでcurlコマンドの出力がエディタで開かれて、シェルに渡す前にレビューや修正ができる。もし怪しいと思ったら、テキストを消せばいい。vetの方が安全に見えるよ。(編集:diff機能があって、デフォルトではスクリプトを実行しない。ただし、デフォルトではレビュー用の新しいスクリプトは表示されない。)vipeの利点は、たぶんmoreutilsがシステムのパッケージリポジトリにあったり、すでにインストールされていることが多いってこと。

え、なんでわざわざ別のツールを使うんじゃなくて、これをするために三つ目のツールを持ってくるの? Curl -o script.sh Cat script.sh Bash script.sh なんか面白い発想だね。

何か見落としてる?vet foobar-downloader.shをやったとしても、curl foobar-downloader.sh | bashの代わりに、次のコマンドは結局foobarを実行することになるんじゃないの?「盲目的に信頼」して、foobarリポジトリのソースが侵害されてないかどうかとか、そういうのはどうするの?

いや、最初にスクリプトを見せてくれるって書いてあるから、レビューできるんだよ。俺が理解できないのは、なんでこれにプログラムが必要なのかってこと。スクリプトをファイルにcurlして、catしてレビューすればいいじゃん。

もし盲目的に実行するだけなら、vetは必要ないよ。自動じゃないし、実行する前にスクリプトを確認するチャンスをくれるだけだから。

「curl|bash」の全体の目的は、パッケージマネージャーへの依存をスキップして、ベアボーンのマシンにインストールすることなんだ。インストールツールなしでツールをインストールできるツールをインストールするのは…

でも、その場合はcurl | bashのアンインストールツールも必要だよね。ほとんどのインストールスクリプトは話の半分で、アンインストールの部分が存在しないんだから。

curl|bashを見かけるのは、大体リポジトリソースをパッケージマネージャー(Debian/Ubuntu)に追加するためだね。

ずっと前から、Windowsでcurl | bashを使ってソフトをインストールしてたよね。要は「インストーラーをダウンロードして実行する」ってこと。たまにマルウェアもあったけど、その対策はアンチウイルスソフトだった。今の若い人たちも、歴史の流れがどうなってるか分かるはず。みんな、何も考えずにnpm installやdocker runしてるし。

「その対策はアンチウイルスソフトだった」って、どれくらい効果あったんだろうね?

「他のみんな」は、審査されたアプリがあるアプリストアを使ってるよね(つまり、あるべきだよね)。

みんな、何も考えずにnpm installやdocker runしてるし。まあ…時々、例えば昨日みたいに[1]、考え直すこともあるけどね。

curlとbashを使うと、コードが人間に読めるから、基本的なbashスクリプトの知識があれば簡単に確認できるよね。

Docker内で動いてるソフトウェアは、外で動かすよりも少しサンドボックス化されてるけど、完璧ではないよね。

Windowsは20年以上もACLやセキュリティディスクリプタを持ってるんだよ。Linuxはスーパーユーザーモデルだし。Windows Storeからのインストール、つまり約75%のインストールはサンドボックス化されていて、もはや権限昇格は必要ない。残りの特権インストールはUACモーダルで確認されて、MS Defenderが悪意のあるパターンから守ってる。sudoとWindowsのインストールを比較するのは、30年以上も遅れてるよ。sudoはほとんどすべてのメモリにアクセスできて、生のデバイスアクセスやディスク上のどこにでもアクセスできるんだから。

安全性の問題を除けば、curl | bashよりdebみたいなものを選ぶ理由の一つは、パッケージマネージャーに何をインストールしてるかを知らせることができるからだと思う。依存関係が満たされてない場合に警告してくれるし、各コンポーネントがどこにインストールされてるかも把握してる。debを見ると、ソフトウェアがシステムの他のものとちゃんと連携するだろうって自信が持てる。

俺も古い人間だから、このスレッドを見て思うんだけど、WindowsやMac OSの実験的なことを許さない傾向に対する嫌悪感が足りないよね。みんな、なんか変な中間地点にいる感じで、安全でありながら実験的な環境を期待してるけど、二つの主要なOSは実験的な方を潰すためにできる限りのことをしてるんだよね。面白いことに、それが安全な方を悪化させることもある。忘れないで、何年もAppleとMicrosoftが本当の力を持たせたくない世界にいるんだから。

firejailやbubblewrapを使って、変更をoverlayfsに制限して、スクリプトを実行する前に何をするか確認する方が良くない?

そうなんだけど、すごく使いにくいよね。curl x.sh | firejail --newみたいな感じで、a) overlayfsが欲しいか? b) ネットワーク隔離が欲しいか? c) ホームディレクトリアクセスを許可するか?って聞いてくれるものが必要だよね。それから、実際にインストールされたものを実行するための同等のものも必要だし。これには、インストールスクリプトが何をしたかを調べて、新しいバイナリを公開する必要があるんだ。もちろん、呼び出されたときはサンドボックス内で実行される。人々が「| bash」の怠惰なデフォルトを乗り越えるためには、覚えやすいコマンドが必要なんだ。これらのツールのUIの複雑さが普及を妨げてるよ。

俺の経験では、こういうcurlスクリプトの多くは、別のスクリプトやタールボールのブートストラップで、どこかからダウンロードされて、さらに別のものをダウンロードするんだ。メインのスクリプトだけ見ても何もわからないよ。例えば、rustのインストール手順を考えてみて。まず、ブートストラップ用のバイナリrustupをダウンロードして、それからインストール手順を実行して自分をシステムに埋め込んで、実際のコンパイラをダウンロードするんだ。全体のチェーンを確認するチャンスもないし、何が変更されるかも後になってからじゃないとわからない。さらに、puccinialinみたいなパッケージを通じて、rustベースのPythonパッケージがコンパイルされるときに同じような不可解なインストール手順を踏むシステムもある。言うまでもなく、こういうのは避けて、パッケージマネージャーや手動でやるのがベストだよ。俺はこういうスクリプトは、他に気にしないシステムや、使い捨てのコンテナでしか実行しない。