説明
ユーザー入力や信頼できない外部データを system、developer、instructions などの優先度が高いプロンプト欄に直接入れると、モデルの動作を意図しない方向へ誘導される可能性があります。安全ポリシーの回避、機密情報の漏えい、権限のあるツールの悪用につながるおそれがあります。
想定される影響
- ユーザー入力が、意図したポリシーやモデルの役割を上書きする可能性があります。
- 保護機能の回避、内部指示の露出、機密性の高い操作の悪用につながるおそれがあります。
- 後続のツール呼び出しや処理が、攻撃者の指示に従う可能性があります。
対処方法
- システムプロンプトと開発者の指示は固定し、ユーザー入力は通常のメッセージや構造化されたデータとして渡してください。
- ユーザー入力からポリシーを組み立てず、サーバーが管理する固定プロンプトの対応表から動作を選んでください。
- 外部文書とユーザーのコンテンツを信頼できないデータとして扱ってください。文字列のサニタイズや、優先度の低いメッセージへの配置だけでプロンプトインジェクションを防げると考えないでください。
- ツール呼び出しはモデルの外で認可し、引数のスキーマ、許可リスト、最小権限を適用してください。
例
変更前
javascript
const express = require("express");
const OpenAI = require("openai");
const app = express();
app.use(express.json());
const client = new OpenAI();
app.post("/bad1", async (req, res) => {
await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: req.body.systemPrompt },
{ role: "user", content: "hello" }
]
});
res.send("ok");
});
変更後
javascript
const express = require("express");
const OpenAI = require("openai");
const app = express();
app.use(express.json());
const client = new OpenAI();
app.post("/good", async (req, res) => {
if (typeof req.body.message !== "string") {
return res.status(400).send("bad message");
}
await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "You are a careful support assistant." },
{ role: "user", content: req.body.message }
]
});
res.send("ok");
});
app.post("/good-mode", async (req, res) => {
if (typeof req.body.message !== "string") {
return res.status(400).send("bad message");
}
const SYSTEM_PROMPTS = {
support: "You are a careful support assistant.",
sales: "You are a careful sales assistant.",
};
const mode = String(req.body.mode || "support");
if (!Object.hasOwn(SYSTEM_PROMPTS, mode)) {
return res.status(400).send("bad mode");
}
await client.responses.create({
model: "gpt-4o-mini",
instructions: SYSTEM_PROMPTS[mode],
input: req.body.message
});
res.send("ok");
});
説明:
- 変更前: ユーザー入力が
systemメッセージに直接入り、モデルのポリシーを変更する可能性があります。 - 変更後: システムプロンプトは固定文字列か、サーバーが管理する対応表から選びます。ユーザー入力が文字列であることを検証し、通常のユーザーメッセージかResponsesのテキスト
inputとして渡します。権限の高い役割を指定できるメッセージ配列は受け付けません。