Start Debugging

Agent Framework 1.21: LocalCodeAct がモデル生成の Python にホストの環境変数を渡さなくなりました

Microsoft Agent Framework .NET 1.21.0 に含まれる Microsoft.Agents.AI.LocalCodeAct 1.21.0-preview.260911.1 では、Environment が null のときに CodeAct の Python サブプロセスが親プロセスの環境を継承しなくなりました。1.20 では、生成されたコードが API キーを含むホストのすべての変数を読み取れました。

Microsoft Agent Framework dotnet-1.21.0 は 2026 年 9 月 11 日にリリースされました。その変更履歴のうち 1 行は、実際に集まるであろう注目よりも多くの注目に値します。“[BREAKING] .NET: Isolate LocalCodeAct subprocess environment” (PR #8159) です。Microsoft.Agents.AI.LocalCodeAct を使っていて LocalCodeActProviderOptions.Environment を一度も設定していない場合、このリリースまでは、モデルが書いた Python がホストプロセスのすべての環境変数を読み取れる状態でした。

2 つのドキュメント、1 つの動作

LocalCodeAct は Hyperlight CodeAct プロバイダーのサンドボックスなし版です。モデルが Python を書き、パッケージが AST 検証を通したうえでそれをホスト上の子 python プロセスで実行します。パッケージの README はすでに、サブプロセスは “does NOT inherit the host environment by default” (既定ではホスト環境を継承しない) と約束していました。一方、Environment の XML ドキュメントは逆のことを述べていました。null は継承を意味し、環境を空にしたければ空のディクショナリを渡す、というものです。コードは XML ドキュメントのほうに従っていました。ProcessBridge.ConfigureEnvironment はディクショナリが null のときに早期リターンしていたため、ProcessStartInfo は親の環境をすべて保持したままでした。

これが問題になるのは、バリデーターが意図的に os.environ への読み取り専用アクセスを許可しているからです。そのため、1.20 では次のコードが検証を通過しました。

Environment.SetEnvironmentVariable("FAKE_OPENAI_API_KEY", "sk-leaked-from-host");

var fn = new LocalExecuteCodeFunction("/opt/homebrew/bin/python3.14");
var result = await fn.InvokeAsync(new AIFunctionArguments
{
    ["code"] = "import os\nprint(os.environ.get('FAKE_OPENAI_API_KEY', 'NOT_FOUND'))\nprint(len(os.environ))",
});

このプローブをそのまま .NET 10 のファイルベースアプリ (SDK 10.0.302、macOS、Python 3.14) として、両方のパッケージバージョンに対して実行しました。

1.20.0-preview.260831.1  default options   -> sk-leaked-from-host, 63 variables
1.21.0-preview.260911.1  default options   -> NOT_FOUND, 2 variables
both versions            Environment set   -> NOT_FOUND, 3 variables

execute_code が出力したものは、そのままモデルのコンテキストに戻ります。プロンプトインジェクションで “環境変数を出力して” と指示するだけで、OpenAI のキー、ストレージの接続文字列、あるいは AZURE_CLIENT_SECRET がトランスクリプトに入り込み、そこからエージェントが呼び出せるあらゆるホストツールへと渡り得ました。

1.21 での現在の動作

ConfigureEnvironment は常に startInfo.Environment.Clear() を呼び出し、そのうえで Environment に入れたものだけをコピーするようになりました。null と空のディクショナリは同じ動作になります。Windows では、SYSTEMROOTSYSTEMDRIVECOMSPECPATHEXTTEMPTMP を設定していない場合、親から補完されます。これらがないと Python は標準ライブラリを読み込めないためです。

裏を返せば、生成されたコードが暗黙的に頼っていたものはすべてなくなります。Linux と macOS の PATHHOME も含まれます。マウントしたスクリプトや許可したモジュールが変数を必要とする場合は、明示的に渡してください。

using Microsoft.Agents.AI.LocalCodeAct;

using var provider = new LocalCodeActProvider("/usr/bin/python3", new LocalCodeActProviderOptions
{
    Environment = new Dictionary<string, string>
    {
        ["LOG_LEVEL"] = "INFO",
        ["TZ"] = "UTC",
    },
});

このディクショナリにシークレットを入れないでください。生成されたコードが認証付きの呼び出しを必要とする場合は、資格情報を保持するホストツールを登録し、Python からは await call_tool(...) を通じてそのツールにアクセスさせてください。

同じリリースに含まれる LocalCodeAct 関連の 2 つの変更

PR #8239 はバリデーターを強化し、OS 由来のエイリアス、リフレクションによるアクセス、環境の変更が一貫して拒否されるようにしました。PR #8289 は承認の扱いを Hyperlight に揃えました。登録されたツールのいずれかが ApprovalRequiredAIFunction であれば execute_code 自体も承認が必要になり、LocalCodeActApprovalMode.AlwaysRequire を指定するとすべての実行で承認が必須になります。

これらのどれも LocalCodeAct をサンドボックスにするものではなく、README も警告ボックスで引き続きそう明記しています。コンテナー、VM、または Foundry のホステッドエージェントの中で動かすべきものです。モデルが書いたコードにそこまでの準備をする価値があるかどうかをまだ検討中なら、CodeAct と従来のツール呼び出しループの比較 でトレードオフを比較しています。すでに運用しているなら、1.21.0-preview.260911.1 に更新し、Environment に渡している内容を監査してください。

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る