설명
서버가 사용자 입력이나 외부에서 받은 신뢰되지 않은 데이터를 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으로 전달합니다. 역할을 지정할 수 있는 메시지 배열은 받지 않습니다.