SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor

코딩 에이전트 프롬프트 인젝션 공격과 방어

파일, PR 댓글, 웹 페이지, 도구 결과가 공격 표면이 되는 이유를 서버 위협 모델로 정리하고 실제 피해를 줄이는 방어책의 우선순위를 비교합니다.

코딩 에이전트에 대한 프롬프트 인젝션이란

코딩 에이전트에 대한 프롬프트 인젝션은 간단히 정의할 수 있다. 에이전트가 읽는 텍스트가 에이전트가 따라야 할 지시로 처리되는 것이다. 에이전트는 파일, pull request 댓글, 웹 페이지 또는 도구 호출 결과를 연다. 이 모든 내용은 사용자가 직접 보낸 요청과 같은 종류의 텍스트로 전달된다. 공격자가 이러한 텍스트를 제어할 수 있다면, 공격자는 사용자의 세션에 내용을 작성하는 셈이다.

현재 제공되는 모든 에이전트 제품에는 이 특성이 있다. 모델은 하나의 토큰 시퀀스를 받는다. 사용자의 요청, system prompt, 파일 내용과 도구 결과가 하나로 결합되고, 모델은 그다음에 올 내용을 예측한다. 토큰에는 권한을 나타내는 비트가 없다. 어느 부분이 사용자가 승인한 내용이고 어느 부분이 낯선 사람의 README 파일에서 온 내용인지 형식만으로는 구분할 수 없다.

이 문서는 위협 모델을 설명한다. 서버에서 실행 중인 에이전트에 공격자가 제어하는 텍스트가 도달하는 지점, 각 지점에서 공격자가 얻는 것, 그리고 어떤 방어책에 투자할 가치가 있는지를 다룬다. 다른 가이드에서 설명하는 격리 조언은 무엇으로부터 에이전트를 격리하는지 알아야 의미가 있다.

모델이 콘텐츠와 지시를 분리할 수 없는 이유

학습은 도움이 되지만 문제를 해결하지는 못한다. 현재 모델은 검색된 텍스트를 의심하도록 학습되며, 조잡한 시도는 많이 거부한다. 그러나 거부는 규칙이 아니라 확률이다. 공격자는 표현을 바꾸고 다시 시도할 수 있으며, 아무도 예상하지 못한 형식으로 텍스트를 숨길 수도 있다. 시도할 수 있는 표현의 수를 제한하는 장치도 없다.

OWASP GenAI 프로젝트는 이를 LLM01:2025 프롬프트 인젝션으로 추적하며, 두 가지로 나눈다. 직접 인젝션은 사용자가 입력한 프롬프트가 모델의 동작을 변경하는 경우다. 간접 인젝션은 웹사이트나 파일 같은 외부 콘텐츠를 모델이 처리할 때 그 콘텐츠가 모델의 동작을 변경하는 경우다. 서버에서는 간접 인젝션이 중요하다. 에이전트는 사용자가 입력하는 텍스트보다 훨씬 많은 텍스트를 읽기 때문이다.

최초의 체계적인 연구는 Greshake와 동료들의 Not what you've signed up for (2023)다. 이 연구에서 기억해야 할 결론은 다음 문장이다. 애플리케이션이 도구를 호출할 수 있는 모델에 검색된 텍스트를 전달하면, 해당 텍스트를 처리하는 일은 임의 코드 실행에 가깝다.

읽기가 침해로 이어지는 조건

악성 텍스트를 읽는 것만으로는 손상이 발생하지 않는다. 손상이 발생하려면 시스템 밖으로 나갈 경로가 있어야 한다.

Simon Willison은 2025년 6월에 이 조합을 치명적 삼요소라고 명명했다. 비공개 데이터를 보유하고, 신뢰할 수 없는 콘텐츠에 노출되며, 데이터를 외부로 전송할 수 있는 에이전트는 대화를 통해 첫 번째 요소를 세 번째 경로로 내보내도록 유도될 수 있다.

VPS에서 실행하는 코딩 에이전트는 첫날부터 이 조건을 모두 갖춘다. 비공개 데이터는 소스 코드, .env 파일, SSH 키, 셸 기록이다. 신뢰할 수 없는 콘텐츠는 에이전트가 읽는 모든 저장소, 페이지, 도구 결과다. 외부로 나가는 경로는 git push, curl, npm publish, pull request 본문 또는 터미널에 출력되어 사용자가 클릭하는 링크다.

두 번째 조건은 제거할 수 없다. 신뢰할 수 없는 텍스트를 읽는 것이 에이전트를 사용하는 목적이기 때문이다. 따라서 실제로 적용할 수 있는 모든 방어는 나머지 두 조건을 대상으로 해야 한다.

서버에서 신뢰할 수 없는 텍스트가 코딩 에이전트에 도달하는 경로

에이전트가 작업하는 저장소

체크아웃에 있는 모든 파일은 입력입니다. 소스 주석, README.md, 변경 로그, 테스트 픽스처, 벤더 코드, 에이전트 지침 파일 자체가 모두 포함됩니다. CLAUDE.md, AGENTS.md 및 이에 해당하는 파일도 마찬가지입니다. 코드베이스를 이해하라는 요청을 받은 에이전트는 이러한 파일을 읽습니다. 그것이 요청한 작업이기 때문입니다.

공격자는 저장소를 클론한 뒤 에이전트를 연결하는 모든 사용자에게 접근할 수 있습니다. 지침 파일은 지침으로 읽히도록 만들어졌기 때문에 가장 직접적인 경로입니다. 예를 들어 pull request에서 CLAUDE.md에 유용한 4줄과 에이전트의 동작을 바꾸는 1줄을 추가하면, 사람이 검토할 때 대충 지나칠 수 있습니다.

이슈, pull request 및 코드 검토 댓글

이슈 추적 시스템에 외부 사용자가 입력할 수 있는 내용은 사용자가 에이전트에 분류를 요청하는 순간 에이전트에 전달됩니다. 2025년 5월, Invariant Labs는 정확히 이러한 형태의 GitHub MCP 조사 결과를 공개했습니다. 한 개발자의 에이전트는 공개 저장소 1개와 비공개 저장소에 접근할 수 있었습니다. 공격자는 공개 저장소에 이슈를 등록했습니다. 개발자가 에이전트에 열린 이슈를 확인하도록 요청하자, 에이전트는 비공개 저장소의 내용을 읽고 이를 공개 영역의 pull request에 작성했습니다.

이 보고서가 설명하는 것은 MCP 서버의 코드 결함이 아니라 아키텍처 문제입니다. 에이전트는 범위가 지나치게 넓은 액세스 토큰 1개를 보유했고, 공개 입력함에서 읽을 수 있었으며, 쓰기 권한도 있었습니다. 일반적인 의미에서 잘못 구성된 부분은 없었습니다. 따라서 해결책은 패치가 아니라 권한 범위를 제한하는 것입니다.

에이전트가 가져오는 웹 페이지

문서, 포럼 답변, 공급업체 페이지, 검색 결과가 해당합니다. 이들에는 사용자보다 에이전트를 대상으로 작성된 텍스트가 포함될 수 있습니다. HTML을 텍스트로 변환하면 공격자가 사용할 수 있는 공간이 더 넓어집니다. 브라우저에는 표시되지 않는 콘텐츠도 모델에 전달되기 때문입니다.

공격자는 에이전트가 가장 적게 감시되는 순간에 제어권을 얻습니다. 에이전트가 검색 중 가져온 페이지의 전체 텍스트를 읽는 사람은 없습니다.

MCP 도구 출력

MCP (model context protocol)는 에이전트를 외부 도구에 연결하는 일반적인 방법입니다. 결과는 텍스트로 반환되어 컨텍스트 창에 바로 들어갑니다. 여기에는 한 가지가 아니라 2개의 공격 표면이 있습니다. 도구가 반환하는 데이터가 하나입니다. 모델이 도구 호출 시점을 결정하기 위해 읽는 도구 자체의 이름과 설명이 다른 하나입니다. 또한 사용자가 제어하지 않는 서버는 호출 사이에 이 둘 중 어느 것이든 변경할 수 있습니다.

공격자가 한 도구의 출력에 텍스트를 삽입하면 에이전트가 사용하는 다른 모든 도구에 도달할 수 있습니다. 이 때문에 중요도가 낮은 기능에 대한 주입이 중요도가 높은 기능을 실행하게 됩니다.

CI 로그, 빌드 출력 및 종속성 메타데이터

npm install는 사용자가 작성하지 않은 패키지의 텍스트를 출력합니다. 테스트가 실패하면 라이브러리의 assertion 메시지가 출력됩니다. continuous integration (CI) 작업 로그에는 서드파티 출력이 수천 줄 포함됩니다. 에이전트에 실패한 빌드를 수정하도록 요청하면 에이전트는 이 내용을 모두 읽습니다.

이 경우 공격자는 빌드 머신에 도달합니다. 빌드 머신에는 일반적으로 배포 자격 증명과 레지스트리 토큰이 저장되어 있으며, 노트북보다 주의가 덜 집중되는 경우가 많습니다.

공격자가 실제로 얻는 것

다음 4가지 결과를 고려해야 한다.

자격 증명 탈취. 에이전트 프로세스가 읽을 수 있는 항목은 모두 대상이 된다. 환경 변수, ~/.aws/credentials, ~/.ssh, gh 토큰, Docker 구성 파일이 포함된다. 이러한 정보를 외부로 전송하는 데 curl는 필요하지 않다. 브랜치에 커밋하거나, pull request 설명에 작성하거나, 패키지를 레지스트리에 게시하거나, 공격자가 제어하는 이름을 DNS에 조회하는 것만으로도 데이터가 서버 외부로 이동한다.

사용자가 승인하는 코드 변경. 에이전트가 하는 일이 코드 작성이므로, 미묘하게 잘못된 한 줄을 작성하게 만드는 것이 가장 쉽게 달성할 수 있는 결과다. 종속성을 추가하거나, 토큰을 다른 곳으로 전송하는 로그에 기록하는 호출을 추가하는 경우가 이에 해당한다.

지속성. 한 번 작성한 파일은 모델이 더 이상 관여하지 않아도 계속 작동한다. .git/hooks의 hook, package.json에 있는 postinstall 스크립트, 셸 시작 파일에 추가한 한 줄, CLAUDE.md에 추가한 줄이 그 예다. 다음 명령이 해당 항목을 실행한다.

네트워크 내부로의 이동. 에이전트는 배치한 위치에서 실행된다. 해당 서버가 loopback의 데이터베이스, 내부 관리 서비스, 클라우드 제공업체의 metadata service 또는 사설 네트워크의 다른 호스트에 연결할 수 있다면, 에이전트를 구동하는 모든 요소도 동일한 대상에 연결할 수 있다.

자동 승인 모드는 마지막 확인 절차를 제거한다

기본 모드에서는 Claude Code가 명령을 실행하거나 파일을 수정하기 전에 확인을 요청한다. 이 프롬프트는 앞서 설명한 모든 공격 표면과 실제 동작 사이에 놓인 사람의 확인 절차다. 프롬프트를 제거하는 모드는 이 확인 절차도 제거한다.

문서는 bypassPermissions에 대해 명확히 설명한다. Claude Code가 손상을 일으킬 수 없는 컨테이너나 VM 같은 격리된 환경에서만 사용해야 한다. 자동 모드는 더 완화된 방식이며, 작업이 요청과 일치하는지 확인하는 백그라운드 안전성 검사를 수행하면서 도구 호출을 자동 승인한다. 이러한 검사는 많은 문제를 발견한다. 그러나 여전히 모델 출력에 대한 모델의 판단이므로, 경계선이 아니라 필터로 간주해야 한다.

관리자는 두 가지 모두 제거할 수 있다. 설정 파일에서 permissions.disableBypassPermissionsMode 또는 permissions.disableAutoMode을(를) "disable"로 설정하고, 체크아웃한 프로젝트가 재정의할 수 없도록 해당 파일을 관리형 설정에 배치한다. Claude Code 자동 모드 및 권한 규칙 가이드에서 각 규칙이 적용되는 위치를 설명한다.

효과를 기준으로 정렬한 방어책

이 항목들은 어느 것도 근본적인 해결책이 아니다. 각 항목은 에이전트가 보유하는 범위를 줄이거나, 보유한 것을 사용해 할 수 있는 작업의 범위를 줄인다.

  1. 폐기하고 다시 구축할 수 있는 머신을 사용한다. 침해가 사고 대응이 아니라 1시간의 복구 작업으로 끝나게 한다.
  2. 자신의 자격 증명과 분리되고, 하나의 저장소로 범위가 제한되며, 수명이 짧은 자격 증명을 사용한다.
  3. 에이전트의 명령이 상속하는 환경에 장기 보관 비밀을 두지 않는다.
  4. 에이전트가 시작하는 모든 프로세스에 적용되는 운영 체제 수준의 네트워크 송신 및 파일 접근 제어를 사용한다.
  5. 쓰기와 네트워크 호출에 대한 승인 프롬프트를 계속 활성화한다.
  6. 이름을 지정할 수 있는 특정 작업에는 결정론적인 최후 방어선으로 hook을 사용한다.
  7. 병합하기 전에 diff를 읽는다.

순서가 중요하다. 1번부터 4번까지는 모델이 공격자에게 완전히 장악된 경우에도 적용된다. 5번부터 7번까지는 사람이 주의를 기울여야 하며, 장시간 에이전트를 실행하면 바로 그 주의가 사라진다.

버릴 수 있는 머신에 에이전트를 배치한다

checkout과 범위가 제한된 token 하나를 보유한 VPS는 자신의 key가 들어 있는 laptop보다 훨씬 작은 공격 대상이다. 에이전트는 login account나 root가 아니라 별도의 권한 없는 사용자로 실행한다. 코딩 에이전트용 폐기 가능한 VMVPS에서 최소 권한 사용자 사용에 관한 가이드에서 설정을 다루며, VPS에서 Claude Code를 안전하게 실행하기에서는 일상적인 운영 형태를 다룬다.

환경에서 비밀을 제거한다

환경 변수는 모든 자식 프로세스가 읽을 수 있다. 따라서 에이전트가 실행하는 모든 명령도 읽을 수 있다. Claude Code의 sandbox는 각 sandbox 명령을 실행하기 전에 지정한 변수를 해제할 수 있다. Linux에서는 먼저 두 package가 필요하다.

sudo apt-get install bubblewrap socat

그 다음 ~/.claude/settings.json에 다음을 추가한다.

{
  "sandbox": {
    "enabled": true,
    "network": {
      "allowedDomains": ["github.com", "*.npmjs.org"]
    },
    "credentials": {
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    }
  }
}

deny 항목은 각 sandbox 명령을 실행하기 전에 해당 변수를 해제한다. allowedDomains은 sandbox 명령이 접근할 수 있는 host를 지정한다. credentials 블록에는 Claude Code v2.1.187 이상이 필요하며, 이는 August 2026에 확인된 내용이다. 세션에서 /sandbox를 실행하면 어떤 계층이 활성화되어 있고 어떤 dependency가 누락되었는지 확인할 수 있다. 애초에 해당 머신에 어떤 비밀이 존재해야 하는지를 결정하는 일이 작업의 더 큰 절반이다. AI 에이전트가 비밀에 접근하지 못하게 하기에서 이 문제를 다룬다.

운영 체제에서 네트워크 송신을 차단한다

Firewall rule은 모델이 무엇을 결정했는지와 관계없이 적용된다. 에이전트를 전용 agent 사용자로 실행한 다음, 해당 사용자가 보내는 트래픽을 차단한다.

table inet agentcage {
  chain output {
    type filter hook output priority filter; policy accept;
    meta skuid "agent" ct state established,related accept
    meta skuid "agent" oif lo accept
    meta skuid "agent" counter drop
  }
}

이렇게 하면 agent 사용자는 loopback만 사용할 수 있다. 따라서 해당 사용자의 트래픽은 같은 머신에서 실행하는 proxy를 거쳐야 하며, hostname allowlist는 proxy가 보유한다. https_proxy가 해당 proxy를 가리키도록 설정하면 client는 CONNECT 요청을 보내고 proxy가 name lookup을 수행한다. 따라서 에이전트 자체에는 outbound DNS(Domain Name System)가 필요하지 않다. sudo nft list ruleset로 설정을 확인하고, 에이전트가 새로운 대상에 접근하려고 할 때 drop rule의 counter가 증가하는지 관찰한다.

Firewall을 변경할 때는 두 번째 SSH 세션을 열어 둔다. Container runtime이 이러한 rule에 어떤 작업을 수행하는지도 확인한다. Docker는 자체 chain을 작성하며, published Docker port가 ufw를 우회하는 방식에서 그로 인해 발생하는 예상 밖의 동작을 설명한다.

Hook: 모델이 말로 우회할 수 없는 검사

Permission rule과 hook은 모델이 아니라 Claude Code가 적용한다. 문서에도 명확히 설명되어 있다. prompt 또는 CLAUDE.md의 instruction은 Claude가 시도하는 작업을 정하지만, Claude Code가 허용하는 작업을 변경하지는 않는다. 이 구분이 핵심적인 가치다. CLAUDE.md에 있는 "never run curl" 한 줄은 injection된 문단이 반박할 수 있는 제안일 뿐이다. Hook은 exit code를 반환하는 process다.

.claude/settings.jsonPreToolUse hook을 등록한다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/no-egress.sh"
          }
        ]
      }
    ]
  }
}

Hook은 tool call을 JSON 형식으로 standard input에서 받는다. Exit code 2는 call을 차단하고 standard error의 사유를 Claude에 표시한다. Exit code 0은 call이 일반 permission flow를 거쳐 계속 진행되도록 한다.

#!/usr/bin/env bash
# PreToolUse: stdin holds the tool call, exit 2 blocks it.
cmd=$(jq -r '.tool_input.command // ""')
if printf '%s' "$cmd" | grep -qE '(^|[;&|]|\s)(curl|wget|nc|ncat)(\s|$)'; then
  echo "Blocked: this repository does not allow outbound network commands." >&2
  exit 2
fi
exit 0

이제 한계를 분명히 하자. 이것은 shell string에 대한 denylist이며, shell string을 대상으로 한 denylist에는 누락이 생긴다. python3 -ccurl라는 단어를 사용하지 않고 socket을 열 수 있다. make deploy target은 같은 call을 한 단계 더 아래에 숨길 수 있다. 이름을 지정할 수 있는 실수에는 hook을 작성하고, 실제로 의존하는 경계는 kernel 또는 network에 설정한다.

Permission deny rule에는 알아 두어야 할 matching 범위의 제한이 있다. ReadEdit deny rule은 Claude 자체의 file tool과 Bash에서 Claude가 인식하는 file command를 대상으로 하며, 예를 들어 cat, head, tail, sed가 이에 해당한다. Python 또는 Node script가 직접 file을 여는 경우에는 적용되지 않는다. Rule은 먼저 deny, 다음 ask, 마지막 allow 순서로 평가된다. 따라서 deny rule에는 allowlist 예외를 추가할 수 없다.

{
  "permissions": {
    "deny": [
      "Read(.env)",
      "Read(./secrets/**)",
      "Bash(git push *)"
    ]
  }
}

외부로 나가는 내용을 관찰하고 diff를 읽는다

에이전트 실행은 diff와 일련의 network call을 생성한다. 무엇이든 merge하거나 deploy하기 전에 둘 다 확인해야 한다. self-hosted security review pass로 diff를 검토하면 사람이 대충 훑어보는 것과는 다른 유형의 변경을 발견할 수 있다. 코딩 에이전트가 머신 밖으로 전송하는 내용 파악에서는 정상적인 traffic의 형태를 설명하므로, 비정상적인 request를 쉽게 식별할 수 있다.

아직 해결되지 않은 문제

현재는 콘텐츠와 지시를 안정적으로 분리할 방법이 없다. 출시된 모든 방어 수단은 실패율이 있는 필터이거나, 실패했을 때의 영향을 제한하는 장치다. 텍스트의 특정 구간을 어떤 경우에도 따라서는 안 되는 데이터로 표시하는 기능은 스택 어디에도 없다.

필터는 실제로 도움이 되지만 실패하기도 한다. 대부분의 인젝션 시도를 탐지하는 분류기라도 매번 정확해야 하지만, 공격자는 한 번만 성공하면 된다. 방어 수단의 공개 성공률이 다음 공격의 출발점일 뿐 보장이 아닌 이유는 이 비대칭성에 있다.

가장 가능성이 큰 연구는 모델 수준보다 설계 수준에서 진행되고 있다. Defeating Prompt Injections by Design의 CaMeL(Debenedetti와 동료들, 2025)은 먼저 신뢰된 요청에서 제어 흐름과 데이터 흐름을 추출한다. 따라서 신뢰할 수 없는 데이터가 프로그램의 동작을 변경할 수 없다. 그런 다음 도구를 호출할 때 capability 검사를 적용한다. 이 논문에 제시된 AgentDojo 벤치마크 수치는 그 대가를 보여 준다.

ChartAgentDojo tasks solved, published figures from the CaMeL paper (2025)
The data behind this chart
[
  {
    "label": "Undefended agent",
    "tasks_solved_pct": 84
  },
  {
    "label": "CaMeL",
    "tasks_solved_pct": 77
  }
]

방어 기능이 없는 에이전트는 작업의 84%를 해결했다. CaMeL은 보장을 제공하면서 77%를 해결했다. 이 수치는 하나의 벤치마크에서 논문이 공개한 결과일 뿐이며, 사용자의 워크로드를 측정한 결과가 아니다. 두 수치의 차이는 현재 실제 보장을 적용하는 데 드는 비용에 대략 해당한다.

이와 같은 설계가 매일 사용하는 도구에 적용되어 출시될 때까지는 에이전트가 언젠가 침해될 것을 전제로 계획하고, 그 사건이 별일이 되지 않도록 만들어야 한다. 이것이 바로 폐기 가능한 머신, 범위를 제한한 자격 증명, 통제된 아웃바운드 연결, diff를 확인하는 습관이 필요한 이유다.

FAQ

프롬프트 인젝션을 막기 위해 에이전트에게 파일의 지시를 무시하라고 말하면 됩니까?

아니요. 해당 문장은 공격과 동일한 컨텍스트 창에 있는 텍스트이며, 공격자의 텍스트와 동등한 조건에서 경쟁합니다. Claude Code 문서는 이 경계를 명확히 설명합니다. 프롬프트 또는 CLAUDE.md의 지시는 에이전트가 수행하려는 작업의 방향을 정하지만, 도구가 허용하는 작업 자체를 변경하지는 않습니다. 지시 파일은 의도를 나타내는 문장으로 취급하고, 실제로 의존하는 내용은 권한 규칙, PreToolUse hook 또는 방화벽 규칙에 설정합니다.

에이전트가 내 저장소만 다루는 경우에도 프롬프트 인젝션이 실제 위험이 됩니까?

그렇습니다. 저장소에는 사용자가 작성하지 않은 텍스트가 가득하기 때문입니다. 종속성 README 파일, lockfile URL, 테스트 fixture, vendored code, npm install의 출력은 일반적인 작업 중에 모두 유입됩니다. 이슈 트래커나 문서 사이트에서 가져오는 내용도 같은 방식으로 유입됩니다. 에이전트가 읽는 내용이 많을수록 위험은 커집니다. 유용한 에이전트는 많은 내용을 읽습니다.

에이전트를 컨테이너에서 실행하면 이 문제가 해결됩니까?

피해 범위를 줄일 수는 있지만, 자격 증명도 함께 제거한 경우에만 그렇습니다. SSH agent가 전달되고, 환경 변수에 cloud 자격 증명이 있으며, 네트워크에 제한 없이 접근할 수 있는 컨테이너는 공격자에게 호스트가 가진 권한 대부분을 넘겨줍니다. 컨테이너가 실제로 제공하는 이점은 삭제할 수 있는 파일 시스템과 egress 규칙을 적용할 수 있는 깨끗한 환경입니다. 여기에 하나의 저장소로 범위를 제한한 token을 함께 사용합니다.

위험을 가장 크게 줄이는 단일 변경은 무엇입니까?

에이전트의 명령이 상속하는 환경에서 장기간 유효한 자격 증명을 제거한 다음, 해당 시스템에 default-deny egress 정책을 적용합니다. 이 두 가지를 함께 적용하면 치명적인 3요소의 세 번째 조건이 차단됩니다. 텍스트가 여전히 에이전트를 가로챌 수는 있지만, 에이전트가 접근할 수 있는 데이터는 유용한 목적지로 전송되지 못합니다. 승인 프롬프트와 diff 검토도 도움이 됩니다. 그러나 이러한 방법은 장시간 실행되는 작업 동안 사람이 계속 주의를 기울여야 하므로, 앞의 두 변경보다 우선순위가 낮습니다.