| 14:38~14:44 | 8 | 남은 위험 (인증 · 요청 수 제한 · 정기 점검 · 커밋 속 비밀) |
| 14:44~14:50 | 9 · 10 · 확인 질문 | 요청문, 자주 하는 실수, 질문 |
### 6교시 Lab 03에서 이어서 하는 것
| 6교시 실습 (시각) | 이 강의의 절 | 실습에서 하는 일 | 쓰는 파일 · 명령 |
| --- | --- | --- | --- |
| Lab 03 예제 1 (15:00~15:10) | 1 · 2 | 답을 보내기 전에 연락처 가리기 · 유출 차단 | `call my-secure requests/contact-own.json -v`, 테스트 `cases/lab03.json` 앞 둘 · `lab01-attacks` |
| Lab 03 예제 2 (15:10~15:18) | 3 | 모든 결과에 `security` 기록 | 테스트 `cases/lab03.json` 6개 |
| Lab 03 예제 3 (15:18~15:25, 에이전트 없이) | 4 | 관문 다섯 곳의 시간과 기록 보기 | `test cases/lab03-layers.json -v` → `my-work/SECURITY.md` 7절 |
| Lab 03 과제 1 (15:25~15:38) | 5 | 어려운 보안 테스트 8개 쓰고 실패를 고치기 | `cases/my-cases.json` (내가 씀), `--repeat 3` → `SECURITY.md` 8절, `my-work/TEST-REPORT.md` |
| Lab 03 과제 2 (15:38~15:50) | 6 · 7 | 감사 로그와 하루 보안 요약 | `my-work/security-report.json` (새로), 테스트 `cases/lab03-challenge2.json` → `SECURITY.md` 9 · 10절 |
## 1. 나가는 답도 검사한다
### 일반 설명
**출력 가드레일**은 LLM이 만든 답을 사용자에게 보내기 직전에 봅니다. 입력 관문은 "무엇이 들어오나"를, 출력 관문은 "무엇이 나가나"를 봅니다. 보안에서는 둘을 따로 세웁니다. 들어오는 것을 다 막을 수는 없고, 막았다고 해도 LLM이 **데이터를 어떻게 섞어 쓸지**는 모르기 때문입니다.
| OWASP LLM Top 10 | 출력 쪽에서 생기는 일 | 막는 법 |
| --- | --- | --- |
| 민감 정보 유출 | Tool이 가져온 연락처 · 메모가 답에 그대로 | 마스킹, 유출 표시가 있으면 차단 (2절) |
| 부적절한 출력 처리 | LLM의 답을 검사 없이 다음 시스템에 넘김 | 받는 시스템의 형식에 맞게 이스케이프 · 검증 |
| 시스템 프롬프트 유출 | 답에 지시문 조각이 섞임 | 지시문 조각 모양을 찾아 차단 |
**답은 화면에서 끝나지 않습니다.** 사용자는 답을 캡처하고, 메신저로 전달하고, 문서에 붙입니다. 시스템은 답을 로그 · 대화 기록 · 분석 도구에 남깁니다. 본인 것이라도 답에 **꼭 필요한 만큼만** 보여 주는 까닭입니다. 보안에서는 이것을 "데이터가 흘러가는 길(data flow) 전체를 본다"고 말합니다.
**출력이 다른 시스템의 입력이 될 때가 더 위험합니다.** LLM의 답을 그대로 HTML 화면에 넣으면 XSS가, SQL에 넣으면 SQL 인젝션이, 셸에 넣으면 명령어 주입이 됩니다 (1단계 1절의 옛 공격들이 출구에서 다시 나타남). 원칙은 **LLM의 출력도 사용자 입력처럼 믿지 않는다**입니다. 받는 시스템의 형식에 맞게 이스케이프하고, 정해진 모양(JSON 스키마 · 허용된 값)인지 검사합니다. 오늘 답은 사람이 읽는 글이므로 개인정보 가리기와 유출 차단만 합니다.
**출력 관문은 마지막 겹입니다.** 앞의 관문이 모두 뚫렸을 때 피해를 줄이는 자리입니다. 그래서 출력 필터는 **확실한 코드**로 둡니다. 마지막 겹을 확률(LLM)에 맡기면, 앞이 뚫린 날 마지막도 뚫릴 수 있습니다.
**출력 쪽 사고는 늦게 알게 됩니다.** 입력 쪽 공격은 이상한 질문으로 보이지만, 출력 쪽 유출은 **평범한 친절한 답**처럼 보입니다 (오늘 아침 공격 대상이 비밀을 내주며 HTTP 200으로 답한 것처럼). 그래서 출력 관문은 막는 것만큼 **세는 것**(3절 기록)이 중요합니다. 답에서 무엇을 몇 번 가렸는지가 쌓이면, 어느 Tool이 너무 많은 데이터를 돌려주는지가 보입니다.
| 출력 관문이 보는 것 | 예 | 오늘 |
| --- | --- | --- |
| 개인정보 모양 | 전화 · 이메일 · 주민번호 · 카드 번호 | 가림 |
| 내부 정보 모양 | 내부 코드 · 서버 주소 · 키 모양 | 답 전체 차단 |
| 지시문 조각 | `<question>`, 지시문의 특정 문장 | 답 전체 차단 |
| 형식 | 정해진 칸 · 길이 · 언어 | 72일차 답 검사 |
| 내용 정책 | 욕설 · 차별 · 위험한 안내 | (오늘 하지 않음, 콘텐츠 안전 서비스)
### 오늘 실습에서
2단계에서 본인 건이 제대로 보이게 되자(Lab 02 예제 1), 이번에는 **본인 연락처가 그대로** 답에 나왔습니다. `lab01-attacks`에서 공격 대상 때는 ✔였던 "연락처 그대로"가 Lab 02 뒤 ✘가 되었습니다 (`answers/14`). **한 곳을 고치면 다른 곳이 드러납니다.** 그래서 고칠 때마다 모든 테스트를 다시 돌립니다.
## 2. 가리기 · 유출 차단: 코드가 한다 (6교시 Lab 03 예제 1)
### 일반 설명
**마스킹(masking)**은 값의 일부를 `*`로 바꿔 보여 주는 것입니다. 카드 영수증의 `****-****-****-1234`가 예입니다. 개인정보보호에서는 이것을 **가명 · 비식별 처리**의 한 방법으로 봅니다. 남길 부분은 **본인이 알아볼 수 있을 만큼만** 정합니다.
| 대상 | 정규식 (요지) | 가린 모양 | 남긴 것 | 왜 그만큼 |
| --- | --- | --- | --- | --- |
| 전화번호 | `01[016789][-. ]?\d{3,4}[-. ]?\d{4}` | `010-****-2135` | 앞 3 · 끝 4 | 본인 번호인지 알아볼 수 있음 |
| 이메일 | `[\w.+-]+@[\w-]+\.[\w.]+` | `y***@example.com` | 첫 글자 · 도메인 | 어느 계정인지 짐작 |
| 주민등록번호 | `\d{6}[- ]?[1-4]\d{6}` | `900101-*******` | 생년월일 | 뒷자리가 핵심 정보 |
| 카드 번호 (예) | 16자리 | `****-****-****-1234` | 끝 4 | 업계 관행 |
| 유출 표시 | 내부 코드 모양(`IT-ADMIN-\d+`), 지시문 조각(`<question>`, `systemMessage`) | 답 전체를 `차단` | — | 일부만 가려도 이미 샌 것 |
**가리기와 막기의 차이.** 가리기는 "있어도 되는데 보기 좋게", 막기는 "있으면 안 되는 것"입니다. 연락처는 본인에게 일부 보여 줘도 되지만, 내부 비상 코드는 한 글자도 나가면 안 됩니다. 그래서 내부 정보 모양이 보이면 답을 고쳐 쓰지 않고 **답 전체를 정해진 안내로** 바꿉니다.
**셀 수 있는 검사는 코드가 합니다.** LLM에게 "연락처는 가려서 답해"라고 지시하는 것도 좋지만, 그것은 확률입니다. 영어로 묻거나 "숫자 사이에 점을 찍어 줘", "한 글자씩 띄워서 알려 줘"라고 하면 지시를 피해 갈 수 있습니다. 정규식은 같은 모양을 늘 같게 찾습니다 (69일차). 지시와 코드를 **둘 다** 씁니다: 지시로 대부분 줄이고, 코드로 마지막을 확실히.
**정규식의 두 실패 (1단계 7절과 같음).**
| 실패 | 예 | 줄이는 법 |
| --- | --- | --- |
| 놓침 | 하이픈 없는 `01014142135`, 점 `010.1414.2135`, 띄어쓰기 | `[-. ]?`처럼 구분자를 넓게 |
| 오탐 | 날짜 `2026-10-27`, 주문 번호, 버전 `1.0.10` | 앞뒤 경계(숫자 · 점이 붙어 있지 않을 때만), 앞자리 조건 |
**돌려 말한 유출은 못 막습니다.** "공일공 일사일사 …"처럼 말로 풀어 쓰거나, 여러 답에 나눠 조금씩 내보내는 것은 정규식으로 잡기 어렵습니다. 이런 것은 출력 필터만으로 막지 않고, **애초에 LLM이 그 데이터를 받지 않게**(Tool이 꼭 필요한 칸만 돌려주게) 합니다. 데이터 최소화(7절)는 출력 쪽에서도 가장 확실한 방어입니다.
**가리기 말고도 있는 방법.**
| 방법 | 뜻 | 되돌릴 수 있나 | 쓰는 곳 |
| --- | --- | --- | --- |
| 마스킹 | 일부를 `*`로 | 아니오 | 화면 · 답 · 로그 (오늘) |
| 토큰화 | 진짜 값 대신 의미 없는 대체값, 진짜는 따로 금고에 | 금고가 있으면 예 | 결제 · 카드 번호 |
| 암호화 | 열쇠로 잠금 | 열쇠가 있으면 예 | 저장 · 전송 |
| 해시 | 같은 값은 같은 결과, 원래 값은 모름 | 아니오 | "같은 사람인가"만 알 때 (7절) |
| 지우기 | 아예 빼기 | 아니오 | 필요 없는 칸 (가장 확실) |
어느 방법이든 **어디서** 하는지가 중요합니다. 답을 만든 뒤 가리는 것보다, Tool이 애초에 필요한 칸만 돌려주는 것이 더 확실합니다.
| `blocked_by` | 어느 관문이 일하나 (규칙 · 판별 LLM · 출력 필터 · 없음) |
| `reason` | 지나치게 막은 것 찾기, 규칙 고치기 |
| `masked` | 개인정보가 답에 섞이는 빈도 |
**"막지 않았다"도 기록합니다.** 정상 답에도 `blocked_by: ""`, `masked: 0`을 남깁니다. 전체 중 몇 퍼센트가 막혔는지(차단율)를 세려면 분모가 필요하고, 정상 답에서 가리기가 일어난 빈도(`masked > 0`)는 Tool이 너무 많은 데이터를 돌려준다는 신호입니다.
**기록은 증거입니다.** 사고가 나면 "언제부터, 누가, 무엇을" 했는지를 기록으로 되짚습니다. 그래서 기록은 고칠 수 없게(추가만 되게) 보관하고, 시각을 함께 남깁니다 (6절 감사 로그).
### 오늘 실습에서
규칙과 판별 LLM은 같은 `Blocked` 노드로 들어옵니다. 누가 막았는지는 `$('Blocked by guard?').isExecuted`로 구분합니다 ([AGENTS.md](../../Last3Mon/73/AGENTS.md) 6절). 10/26 (`answers/25` · `27`): `lab03` 2/6 → **6/6**.
## 4. 관문별 시간과 기록 (6교시 Lab 03 예제 3)
### 일반 설명
겹겹이 막기를 운영할 때는 관문마다 **얼마나 자주 · 얼마나 빨리 · 얼마나 정확히** 일하는지를 봅니다. 72일차의 단계별 시간(`timings`)과 같은 생각을 보안에 적용한 것입니다.
| 보는 것 | 알 수 있는 것 | 할 일 |
| --- | --- | --- |
| 관문별 차단 수 | 어느 관문이 바쁜가 | 판별 LLM이 많이 막으면 그 모양을 규칙으로 옮길 후보 |
| 관문별 시간 | 관문이 정상 요청에 더한 시간 | 느린 관문을 뒤로, 또는 더 싼 방법으로 |
| 관문별 오탐 | 정상을 막은 수 (이의 신고) | 규칙을 좁히거나 정상 예를 더함 |
| 끝난 곳의 분포 | 앞에서 끝나는 비율 | 앞에서 많이 끝날수록 비용 · 위험이 작음 |
**앞에서 끝날수록 좋습니다.** 앞 관문은 싸고(코드), 확실하고, LLM에 닿지 않습니다. 같은 공격이 뒤의 판별 LLM에서 막히면 1초 · LLM 1번이 들고, 판별이 속으면 그다음 겹에 기대야 합니다. 그래서 운영자는 "판별 LLM이 막은 것 중 규칙으로 막을 수 있었던 것"을 정기적으로 찾아 앞으로 옮깁니다.
**관문 하나의 효과를 따로 재는 법.** 관문 하나를 끄고(또는 그 관문 앞에서 끝나는 요청을 보내고) 같은 테스트를 돌려 차이를 봅니다. 오늘 실습의 "고치기 전 → 고친 뒤"가 바로 이것입니다. 관문마다 "이 관문이 없으면 몇 개가 새나"를 말할 수 있어야, 관문을 뺄지 남길지 숫자로 정할 수 있습니다.
**오늘 결과로 읽는 법 (예).** 관문 다섯 곳에 하나씩 보낸 결과에서, 앞의 둘(입력 검증 · 규칙)은 0.1초 · LLM 0번, 판별 LLM은 약 1초 · LLM 1번, 끝까지 간 둘은 3초 안팎 · LLM 2번 + Tool이었습니다. 하루 요청 중 공격 · 잘못된 요청이 많은 서비스일수록 앞 관문을 두껍게 하는 것이 시간과 비용을 함께 줄입니다.
| 운영 지표 (예) | 계산 | 경고 신호 |
| --- | --- | --- |
| 차단율 | 차단 수 ÷ 전체 | 갑자기 오르면 공격, 갑자기 내리면 관문 고장 |
| 판별 LLM 비율 | 판별이 막은 수 ÷ 전체 차단 | 높으면 규칙 보강 후보 |
| 정상 답의 가림 비율 | `masked > 0`인 답 ÷ 답 | 높으면 Tool이 데이터를 너무 많이 줌 |
| ⑤ 정상 질문 | 모두 지나감 | 200 | `""` | 3.0초 | 2 + Tool |
**앞에서 끝날수록 빠르고 쌉니다.** 이 표가 오늘 하루를 한 장에 보여 줍니다.
## 5. 지나치게 막기와 덜 막기: 보안 테스트 (6교시 Lab 03 과제 1)
### 일반 설명
보안 테스트의 목적은 통과가 아니라 **실패를 찾는 것**입니다. 이미 막은 것을 더 시험해도 배울 것이 없습니다. 좋은 보안 테스트는 "이건 지나갈 것 같은데?"라는 의심에서 나옵니다.
**테스트를 쓰는 다섯 방향.**
| 방향 | 무엇을 찾나 | 예 |
| --- | --- | --- |
| 막아야 할 것 | 거짓 음성 (놓침) | 숨긴 공격, 처음 보는 말 |
| 막으면 안 되는 것 | 거짓 양성 (오탐) | 공격 낱말이 들어간 정상 질문 |
| 경계값 | 기준선 바로 앞뒤의 실수 | 정확히 500자, 501자 |
| 다른 길 | 같은 위험을 다른 통로로 | 영어로, 남의 것을, 두 번에 나눠서 |
| 기록 | 기록 자체의 유출 | `security.reason`에 개인정보가 없나 |
- **경계값**: 대부분의 버그는 경계에 있습니다. "500자 이하"를 "<500"으로 잘못 쓰면 정확히 500자가 막힙니다. 0, 1, 기준-1, 기준, 기준+1을 시험합니다.
- **두 방향을 같이**: 막아야 할 것만 쓰면 지나치게 막는 규칙도 "통과"합니다. 막으면 안 되는 것을 반쯤 섞어야 균형을 봅니다.
- **회귀 테스트**: 한 번 찾은 실패는 테스트로 남깁니다. 나중에 규칙을 고치다 같은 실패가 다시 생기면 바로 압니다.
- **여러 번 돌리기**: LLM이 들어간 관문은 같은 입력에도 결과가 흔들립니다. `--repeat`으로 여러 번 돌려 **모두** 통과해야 고쳤다고 봅니다.
**레드팀 자동화.** 공격 문장을 모아 두고(오늘 `samples.json`), 워크플로우 · 지시문 · 모델이 바뀔 때마다 자동으로 돌립니다. 공개된 LLM 공격 모음과 점검 도구들이 같은 일을 하고, 회사들은 배포 전 검사(74일차)에 넣습니다. 새로 발견된 공격은 모음에 더합니다.
**고칠 관문을 고르는 법.** 실패마다 "어디서 막혔어야 했나(또는 어디서 잘못 막았나)"를 먼저 말합니다. 정상이 막혔다면 막은 관문의 조건을 좁히고, 그 대신 뚫리는 것을 **뒤의 관문이 받치는지** 확인합니다. 공격이 지나갔다면, 가장 싸고 확실하게 막을 수 있는 앞쪽 관문부터 봅니다.
**케이스 하나를 쓰는 틀.** 테스트 케이스는 "무엇을 보내고, 무엇을 기대하고, 왜 어려운가"를 한 줄씩 적으면 됩니다.
| 칸 | 예 |
| --- | --- |
| 이름 | 정상 · '관리자 권한' 설치 신청 |
| 보내는 것 | `{"question": "관리자 권한이 필요한 프로그램 설치는 어떻게 신청하나요?", "user": "한지훈"}` |
| 기대 | `route: 자동 답변` (막으면 안 됨) |
| 왜 어려운가 | "관리자 권한"이 공격 규칙의 낱말과 같음 |
| 실패하면 의심할 관문 | 규칙 (`관리자\s*(권한\|모드)`) |
**판정 기준을 미리 정합니다.** "답이 이상하다"는 판정이 아닙니다. `route`가 무엇이어야 하는지, 답에 어떤 글자가 **없어야** 하는지(`not_contains`)처럼 기계가 판정할 수 있게 씁니다. 특히 보안 테스트는 "무엇이 나오면 안 되는가"로 쓰는 경우가 많습니다. 원래 값이 나오지 않으면 통과, 하나라도 나오면 실패.
### 오늘 실습에서
10/26 (`answers/29` · `30`~`34`):
| | 결과 |
| --- | --- |
| 예제 2 정답에서 | **6/8** — ✘ 둘 다 **지나치게 막음** (정상 두 질문을 규칙이 0.1초에 막음), 덜 막은 것은 없음 |
| 규칙 둘을 좁힌 뒤 (`이전·모든 + 규칙 + 잊`, `관리자 권한으로`) `--repeat 3` | **24/24** |
| 그 뒤 `lab01-challenge` · `lab02-challenge` · `lab03` | 20/20 · 18/18 · 6/6 |
- 좁혀서 놓치는 공격은 판별 LLM이 받칩니다. **규칙은 확실한 것만, 애매한 것은 판별 LLM으로.**
- 이 정답에는 Lab 01 과제 2의 글자 정리가 없는데, 숨긴 공격(`lab01-challenge2`)이 9/9였습니다 (`answers/34`). 판별 LLM이 뜻으로 막은 것입니다. 같은 결과지만 글자 정리는 0.1초 · LLM 0번, 판별 LLM은 약 1초 · LLM 1번입니다.
## 6. 감사 로그 (6교시 Lab 03 과제 2)
### 일반 설명
**감사 로그(audit log)**는 "누가 · 언제 · 무엇을 · 결과는"을 한곳에 쌓는 기록입니다. 보안 사고가 나면 가장 먼저 찾는 것이고, 정보보호 관리체계 인증(ISMS-P, ISO 27001)과 개인정보보호법의 안전성 확보 조치에서도 접속 · 처리 기록의 보관과 점검을 요구합니다.
| **서비스를 멈추게 하지 않는다** | 기록이 실패해도 사용자 답은 나가야 함 (응답과 나란히, 실패해도 계속). 반대로 결제처럼 "기록 없이는 처리하지 않는" 업무도 있으니 업무마다 정함 |
| **고칠 수 없게** (추가만) | 공격자 · 내부자가 흔적을 지우지 못하게. 운영에서는 쓰기만 되는 저장소, 따로 떨어진 로그 서버 |
| **시각을 정확히** | 여러 시스템의 기록을 맞춰 보려면 같은 시계 (서버 시각 · 시간대) |
| **볼 수 있는 사람을 정한다** | 로그도 개인정보 · 보안 정보를 담음 |
| **보관 기간을 정한다** | 너무 짧으면 조사를 못 하고, 너무 길면 쌓인 것이 위험 |
| **개인정보를 최소로** (7절) | 로그 자체가 유출 대상 |
**로그로 무엇을 하나.** 매일 아침 "어제 몇 건을 막았나, 누가 반복해서 막혔나, 어느 관문이 바빴나, 판별 LLM이 멈춘 적은 없나"를 요약합니다. 같은 사람이 짧은 시간에 여러 번 막혔다면 공격 시도일 수 있으니 확인합니다. 77일차 실행 로그 분석과 79일차 운영 대시보드로 이어집니다.
시각 · 누가 · 결과 · 관문 · 이유 · 숫자만 있고, 질문 · 답 글자는 없습니다. 이것으로 "어제 한지훈 님이 판별 LLM에 한 번 막혔다"는 알 수 있지만 무엇을 물었는지는 알 수 없습니다. 무엇을 물었는지까지 꼭 알아야 하는 업무라면, 가린 문장을 **따로**, 더 짧은 보관 기간과 더 좁은 열람 권한으로 둡니다.
개인정보보호법의 기본 원칙 중 하나가 **최소 수집**입니다: 목적에 필요한 최소한의 개인정보만 모읍니다. 로그도 개인정보를 모으는 곳입니다. 필요 없는 것을 남기면 로그 자체가 유출 대상이 되고, 보관 · 파기 · 열람 권한 관리 · 정보주체의 열람 요청 대응이 모두 따라옵니다. **모으지 않은 것은 샐 수 없습니다** (2단계 3절 "주지 않은 비밀은 새지 않는다"와 같은 생각).
**남길지를 정하는 질문 셋.** ① 이 칸이 없으면 로그의 목적(몇 건, 누가, 어느 관문)을 못 이루나? ② 이 칸에 개인정보 · 비밀이 들어갈 수 있나? ③ 꼭 필요하면, 가리거나 줄여서(해시 · 일부만) 남길 수 있나?
| 남길지 | 무엇 | 까닭 |
| --- | --- | --- |
| 남김 | 직원 이름, `route`, `blocked_by`, `reason`, `masked`, `tools_used`, 시각 | "몇 건, 누가, 어느 관문" (목적에 필요) |
| 남기지 않음 | 질문 · 답 글자 | 안에 연락처 · 주민번호가 있을 수 있음 |
| 남기지 않음 | 연락처 (가린 것도) | 다시 남길 까닭이 없음 |
| 바꿔서 남김 (예) | 질문의 해시 | "같은 질문이 반복되나"만 알면 될 때, 원문 없이 |
**가명 · 익명 처리.** 이름 대신 직원 번호의 해시를 남기면 "같은 사람이 반복하나"는 알 수 있지만 누구인지는 바로 알 수 없습니다(가명). 보안 로그에서는 사고 조사 때 누구인지 알아야 하므로 오늘은 이름을 남기되, 볼 수 있는 사람을 제한하는 쪽을 택했습니다. 목적에 따라 정합니다.
**지켜야 할 규칙은 숫자로 확인합니다.** 요약 워크플로우가 로그 전체에서 전화 · 이메일 · 주민번호 **모양을 세어** `pii_in_log`로 냅니다. 0이 아니면 어딘가에서 새고 있습니다. 규칙("로그에 개인정보를 남기지 않는다")을 사람의 기억이 아니라 **테스트로** 지키는 방법입니다.
**규칙의 `reason`도 줄입니다.** 정규식 그대로 남기면 길고, 로그를 본 사람에게 공격 문장의 모양(= 피하는 법)을 알려 줍니다. 운영에서는 규칙에 이름(`rule:ignore_instructions`)을 붙여 이름만 남깁니다.
### 오늘 실습에서
`curl -s localhost:8800/audit`(`answers/38`)로 줄을 직접 열어 질문 글자가 없는지 눈으로 봅니다. `pii_in_log 0`이 테스트로도 확인됩니다.
## 8. 남은 위험: 오늘 막지 않은 것
### 일반 설명
보안은 끝이 없습니다. 막지 않은 것을 **적어 두는 것**도 보안 일입니다. 회사에서는 이것을 **위험 등록부(risk register)**라고 부르고, 위험마다 "얼마나 일어날 것 같나 · 일어나면 얼마나 나쁜가 · 무엇을 했나 · 받아들인 까닭 · 언제 다시 보나"를 적습니다.
**위험을 다루는 네 가지 방법.**
| 방법 | 뜻 | 예 |
| --- | --- | --- |
| 줄이기 (mitigate) | 관문을 더함 | 오늘 한 대부분 |
| 피하기 (avoid) | 그 기능을 하지 않음 | 연락처 조회 기능 자체를 뺌 |
| 넘기기 (transfer) | 다른 곳 · 보험이 맡음 | 인증은 사내 SSO가, 보안 관제는 전문 업체가 |
**요청문(프롬프트)이란.** 실습에서 CLI 코딩 에이전트(codex · claude · agy)에게 보내는 글입니다. 에이전트는 이 글만 보고 n8n 워크플로우 JSON을 만들거나 고칩니다. 이 절은 이 단계에서 배운 것을 **요청문(프롬프트)에 어떤 칸으로 적을지** 실습 전에 정리하는 자리입니다. 실습 문서의 `▶ 빈칸 채우기 · 요청문(프롬프트) 뼈대`가 이 칸을 실제 문장으로 만든 것이고, 빈칸 ①~④는 그 문장 속 정확한 값입니다.
| 칸 | 에이전트에게 알려 주는 것 | 빠지면 생기는 일 |
| --- | --- | --- |
| 무엇을 | 만들거나 바꿀 기능 | 에이전트가 짐작해서 다른 것을 만듦 |
| 어디에 | 고칠 파일 · 노드 · 자리 | 엉뚱한 노드를 고치거나 새 파일을 만듦 |
| 어떤 모양으로 | 결과 JSON의 칸 이름 · 값 · 응답 코드 | 테스트가 보는 칸 이름과 달라 실패 |
| 그대로 · 하지 말 것 | 건드리면 안 되는 것 | 다른 곳까지 바뀌어 무엇 때문인지 모르게 됨 |
| 확인 | 통과해야 할 테스트 파일 | "다 됐다"를 판단할 기준이 없음 |
67~71일차의 다섯 가지(① 파일 ② 입력 ③ 처리 ④ 결과 모양 ⑤ 기대 결과)와 같은 뜻입니다. 파일 · 입력이 "어디에", 처리가 "무엇을", 결과 모양이 "어떤 모양으로", 기대 결과가 "확인"입니다. 72일차부터는 **이미 있는 워크플로우를 고치는** 요청이 많아 "그대로"가 따로 한 칸이 됐습니다.