⚠️

⚠️ bun は設定次第でビルド成果物に環境変数を埋め込みます

2024/06/12に公開

https://bun.build/

https://github.com/oven-sh/bun/blob/main/src/env_loader.zig#L285-L302

条件

  1. bun build --target bun または bun build --compile --target bun-darwin-arm64 などでビルドをしていて
  2. ソースコード中で process.env を介した環境変数の参照 (process.env.HOME 等) を使っていて
  3. 参照されている環境変数がビルド時の環境変数に含まれるとき
  4. bun はビルド成果物にその環境変数を文字列リテラルとして埋め込みます。

発生する問題

1. 別環境で動かない

当然ながら、process.env.HOME などをソースコード中で使っている場合、異なる環境での動作に問題が発生する可能性があるというか、まず動かないでしょう。
さらに、リテラルに置換されたということは環境変数を受ける口はもうなくなっているので、実行環境の環境変数を読み取ってくれることはありません。

2. 機密漏洩

環境変数が意図せず埋め込まれることによって、機密情報が漏洩するリスクもあります。
例えば aws-sdk を import している場合を考えてみると、AWS JavaScript SDK は当然内部で process.env.AWS_SECRET_ACCESS_KEY を見ています。そして、ビルド時にそれが環境変数に設定されていた場合はバンドルに埋め込まれます。
環境変数にクレデンシャルを入れるのはそもそもよくないという前提はありつつ、例えば CI 上でビルド成果物をアップロードするために AWS のクレデンシャルを環境変数に入れている、という状況は全くありえない話ではなく、CI の場合は自分だけが注意していればよいわけでもないので危険です。

経緯

bun の Single-file executable で簡単な CLI ツールを作って同僚に渡したところ、認証情報が通りませんでした。これは AWS_PROFILE がリテラルとして埋め込まれていた為です。
JavaScript ランタイムなしで実行できるバイナリが書き出せるのは実際に便利なのですが、思わぬ仕様に驚いてしまいました。 --target bun でビルドする機会は今のところあまりないのですが、Single-file executable を作ろうとすれば自ずと bun-ARCH をターゲットにするので、Single-file executable を試そうと思った人がこの問題に出くわす可能性は高いのではないでしょうか。

現状

この機能を削除する PR も出ていましたが、マージされないままクローズされているので、現在の最新版でもこの挙動です。

回避方法

  • env -i bash -c "$(which bun) --target bun index.ts" 等で環境変数をクリアしたサブシェル内でビルドする。ただし PWD のようにクリアできない環境変数もあるので、完全ではありません。
  • Bun.env を使う。こっちは埋め込まれないらしいです。ただ上述したように外部パッケージを読み込んでいたらどうしようもないことです。
  • (オプションで外せる等あればコメントで教えて下さい)

調べてないこと

  • ちゃんとした回避方法
  • "values from the framework are inserted with a lower priority so that users may override defaults" is 何

Discussion