6月6日、Simon Willisonが「Running Python code in a sandbox with MicroPython and WASM」と題した記事を公開した。この記事では、MicroPythonとWebAssemblyを組み合わせて安全なPythonコード実行環境を構築する手法について詳しく紹介されている。以下に、その内容を紹介する。
プラグインシステムの安全性問題
Willisonは、自身が開発するオープンソースプロジェクト(Datasette、LLM、sqlite-utilsなど)でプラグイン機能を重視している。プラグインシステムは新機能の実験リスクを最小限に抑え、コアアプリケーションに影響を与えることなく機能拡張を可能にする。
しかし、現在のプラグインシステムには重大な欠陥がある。PythonとPluggyを使用したプラグインコードは、アプリケーション内でフル権限で実行されるため、バグや悪意のあるプラグインがシステム全体を破壊したり、プライベートデータを漏洩させる可能性がある。
理想的なサンドボックス環境の要件
Willisonが求めるサンドボックス環境の条件は以下の通りだ:
- PyPIからのクリーンインストール:複数プラットフォーム対応のバイナリホイールを含む
- メモリとCPU制限:
while True: s += "longer string"のような無限ループからの保護 - ファイルアクセス制御:読み書き可能なファイルの厳密な定義
- ネットワークアクセス制御:完全制御下でのみ通信を許可
- ホスト関数との連携:選択的なプラットフォーム機能の公開
- 堅牢性と保守性:十分なドキュメントと継続的なメンテナンス
WebAssemblyが最適解である理由
ブラウザは最も敵対的な環境でコードを実行する。ほぼすべてのページロードで信頼できないコードをダウンロードして実行するからだ。
JavaScriptエンジンは優秀なサンドボックス候補だが、極めて複雑で他のプロジェクトへの組み込みが困難だ。多くのv8-in-Pythonプロジェクトは保守頻度が低く、完全に信頼できないコードでの使用を避けるよう警告している。
WebAssemblyははるかに優れた候補である。設計当初から必要な特性をすべて支援し、ブラウザで約10年間テストされている。wasmtime Python ライブラリは活発にメンテナンスされ、バイナリホイールも提供している。
MicroPythonとWebAssemblyの組み合わせ
Pythonのようなダイナミック言語をWebAssemblyで実行するには、eval()のような言語プリミティブをサポートするため、ランタイムで完全なインタープリターが必要だ。
PyodideはブラウザでのPython実行に優れたパッケージを提供するが、サーバーサイドPythonでの使用はサポートされていない。2024年10月の最新アドバイスでは「PyodideはEmscriptenツールチェーンでビルドされ、ブラウザまたはNode.jsでのみ実行可能」とされている。
MicroPythonは制約のある環境での実行に最適化されたPython 3の軽量実装だ。WebAssemblyも制約のある環境と考えられる。
実装の詳細
WillisonはGPT-5.5 Proに調査を依頼し、Yamamoto TakahashiによるMicroPythonのWASI対応PRを発見した。
最も複雑だった課題は永続的なインタープリター状態の実現だった。使用しているWASMビルドは単一エントリポイントを公開し、インタープリターを開始してコードを実行後、終了する設計だった。
解決策として、MicroPython内でホスト関数get_next_python_code()を呼び出し、それをeval()に渡すアプローチを採用した。このホスト関数は新しいコードが利用可能になるまでブロックし、スレッドとキューで管理される。
from micropython_wasm import MicroPythonSession
with MicroPythonSession() as session:
print(session.run("x = 10\nprint(x)").stdout)
print(session.run("x += 5\nprint(x)").stdout)
print(session.run("print(x * 2)").stdout)
内部的には、スレッドを開始してリクエストキューを設定し、session.run()コマンドでメッセージを送信する。WASM内のMicroPythonインタープリターは__session_next__()ホスト関数の戻りを待機し、コードをeval()で実行後、__session_result__()を呼び出す。
ホスト関数のサポートは78行のC言語で実現され、362KBのWebAssemblyブロブにコンパイルされる。
メモリ制限はwasmtimeで直接サポートされる。CPU制限については、wasmtimeの「fuel」概念を使用してWebAssembly呼び出しが実行できる操作数を制限する。現在は2000万のデフォルトfuel設定で実験中だが、最適な値かは確信がない。
信頼性について
Willisonは自身のソリューションをアルファリリース版として位置付け、重大なリスクを取る意思のない人には推奨していない。自身での使用には十分なテストを実施し、datasette-agent-micropythonプラグインとして出荷した。
GPT-5.5 xhighを使ってサンドボックスからの脱出テストも実施したが、現在のところ成功していない。
この実装が、プロフェッショナルなセキュリティチームと高リスク問題を抱える企業に、WebAssembly上でのPythonサンドボックス化アプローチの採用を促し、独自ソリューションのオープンソース化につながることを期待している。
詳細はRunning Python code in a sandbox with MicroPython and WASMを参照していただきたい。