Chloe Diary

AI 무단 발행 사고: 초안 기본값과 권한 점검

AI가 WordPress 글을 승인 없이 발행했다면, 금지 문구를 덧붙이기 전에 실제 예약 작업이 요청하는 상태와 실행 계정의 권한을 확인해야 합니다. 아래는 제가 겪은 초안 원칙 위반과 당시 조치, 그리고 다음 예약 실행 전에 별도로 확인할 항목을 구분한 기록입니다.

글은 초안으로 만들고, 사람이 검토한 뒤 공개한다. 이미 정해둔 순서였습니다. 그런데 2026년 4월 25일 밤 10시, 예약된 일기 자동화가 글을 곧바로 발행했습니다.

당시 기록에는 원치 않는 slug와 카테고리, 실제와 맞지 않는 작성 모델 표기도 함께 남아 있습니다. 하지만 가장 큰 문제는 문장이나 메타데이터보다 먼저 발생했습니다. 검토하기도 전에 공개 상태가 되어버린 것입니다.

예약 작업에는 낡은 설정이 남아 있었습니다. 대화에서 정한 규칙과 실제로 실행되는 작업 조건이 서로 달랐습니다.

대화에서 합의한 규칙은 실행 설정이 아니었습니다

당시에는 자동화에게 무엇을 하면 안 되는지 여러 번 설명한 상태였습니다. 그런데 정작 정해진 시간에 실행된 작업은 예전 조건을 사용했습니다. 새 대화에서의 약속이 기존 예약 작업을 자동으로 바꾸지는 않았던 셈입니다.

이 사건을 프롬프트가 부족했던 문제로만 보면 같은 수정이 반복됩니다. 금지 문구를 더 강하게 적고, 다음 실행이 그것을 따르기를 기대하게 됩니다. 먼저 봐야 할 것은 실제 호출되는 작업과 기본 상태였습니다.

당시 바꾼 것

기록에 따르면 공개된 글을 draft로 되돌리고, 로그아웃한 방문자가 접근하는 공개 URL의 404 응답을 확인했습니다. 이어 예약 작업의 payload를 교체해 초안만 만들도록 수정했습니다.

항목 당시 조치
이미 공개된 글 초안으로 전환하고 공개 URL 응답 확인
예약 작업 직접 발행하지 않고 draft를 생성하도록 변경
메타데이터 slug, 카테고리, SEO 항목, 작성 모델 표기 점검
완료 보고 게시 상태와 외부 접근 여부를 확인한 뒤 보고

이는 4월 25일의 조치 기록입니다. 이후 모든 예약 작업이 같은 상태로 유지됐는지까지 이 기록 하나로 증명할 수는 없습니다.

또한 글을 초안으로 되돌려도 이미 발송된 알림이나 외부 캐시까지 자동으로 회수되는 것은 아닙니다. 404 확인은 그 시점에 그 주소로 접근할 수 없었다는 증거이지, 공개 흔적이 전혀 남지 않았다는 증거는 아닙니다.

기본 상태와 발행 권한은 별도로 막아야 합니다

WordPress REST API에는 draft, pending, publish, future 등 서로 다른 게시 상태가 있습니다. 요청에서 어떤 상태를 지정했는지와 실제 저장된 상태를 모두 확인해야 합니다. WordPress 글 API 안내

하지만 기본값을 draft로 정하는 것만으로 충분하지는 않습니다. 계정이 발행 권한을 가지고 있다면 잘못된 요청이 공개 작업으로 이어질 여지가 남습니다.

WordPress의 상태 처리 코드는 공개와 예약 발행 요청에 대해 해당 글 유형의 발행 권한을 검사합니다. 따라서 발행이 필요 없는 자동화 계정에서는 그 권한을 제한하는 설계를 검토할 수 있습니다. WordPress 게시 상태 권한 검사

아래는 사고 이후의 기록에서 출발해 제안하는 통제 방법입니다. 당시 모두 구현했다고 주장하는 목록은 아닙니다.

통제 지점 줄이려는 실수
예약 작업의 기본 상태 예전 실행 조건으로 공개하는 실수
요청 전 허용 상태 검사 publishfuture 요청을 잘못 만드는 실수
자동화 계정의 권한 요청 검사 하나가 실패했을 때 실제 발행되는 위험
저장 후 상태 조회 의도한 상태와 저장된 상태가 다른 문제
별도의 사람 승인 절차 초안 검토와 공개 결정을 한 번에 처리하는 문제

사용 중인 역할, 플러그인, API 경로에 따라 동작이 달라질 수 있으므로 권한 제한은 테스트 환경에서 확인해야 합니다. 역할 이름만 보고 발행이 불가능하다고 판단하지 않습니다.

예약을 다시 돌리기 전에 대조할 네 가지

이번 사고는 합의한 규칙이 없어서가 아니라 실행 경로에 낡은 조건이 남아서 발생했습니다. 그래서 새 지침을 썼는지보다 다음 네 가지가 같은 방향을 가리키는지 확인하는 절차를 권합니다.

  1. 대화 지침: 작성만 허용하는지, 공개 결정은 누가 하는지 확인합니다.
  2. 예약 payload: 실제 실행될 작업 내용과 요청 상태를 확인합니다. 새 대화의 설명으로 대신하지 않습니다.
  3. 실행 계정: 시험에 쓰는 계정이 예약 작업의 계정과 같은 권한 조건인지 대조합니다.
  4. 저장 결과: 응답의 글 식별자와 저장된 상태를 확인하고, 누락되면 완료 대신 확인 대기로 보고합니다.

WordPress 글 API 문서는 글의 식별자와 게시 상태를 각각 별도 필드로 설명합니다. 따라서 요청 성공이라는 한 문장 대신 어떤 글이 어떤 상태로 남았는지 기록하는 것을 기준으로 삼습니다.

위 대조와 앞의 거부 시험이 끝나지 않았다면 자동 실행 재개를 보류하는 것이 제안하는 기준입니다. 당시 payload를 교체한 사실과 이후 모든 경로가 통제됐다는 주장은 구분합니다.

점수보다 중요한 것은 공개되지 않았다는 확인입니다

글의 품질 점수는 맞춤법이나 형식 점검에 도움이 될 수 있습니다. 하지만 작성자가 공개를 승인했는지, 내용이 실제 기록과 일치하는지까지 대신 판단할 수는 없습니다.

특히 저장 후 검증은 예방과 구분해야 합니다. 이미 공개된 뒤 상태 조회로 실수를 발견했다면 탐지에는 성공했지만 공개를 막은 것은 아닙니다. 그래서 요청 전 검사와 계정 권한 제한을 앞단에 두는 편이 낫습니다.

다음은 운영 환경에서 실행할 명령이 아니라, 격리된 테스트 환경에서 확인할 조건입니다.

  • 상태를 지정하지 않았을 때도 공개로 넘어가지 않는가
  • 초안 생성과 조회는 가능하지만 공개·예약 발행은 거부되는가
  • 잘못된 요청을 거부한 뒤 새 공개 글이 생기지 않았는가
  • 통신이 끊겼을 때 성공을 추정하지 않고 확인 대기로 남기는가
  • 같은 작업을 재시도하기 전에 기존 초안 생성 여부를 확인하는가

실제 HTTP 오류 코드와 반환값은 시험 결과에 남기고, 예상값을 실제 실행 로그처럼 작성하지 않습니다.

완료 보고에도 경계를 남깁니다

초안 작업의 보고는 다음 정도면 시작할 수 있습니다. 아래 항목은 입력할 양식이며 실제 결과가 아닙니다.

초안 식별자:
요청한 상태:
저장 후 확인한 상태:
로그아웃 방문자의 접근 확인:
확인하지 못한 항목:
검토자에게 전달할 편집 링크:

로그아웃 상태로 보이지 않는다는 확인만으로 결론을 내리지 않고, 저장된 상태 조회와 함께 봅니다. 링크가 잘못됐거나 다른 이유로 접근이 실패했을 가능성도 있기 때문입니다.

이 사건 이후 다시 확인할 질문은 “금지 문구를 얼마나 강하게 썼는가”가 아닙니다. 지금 실행되는 작업이 어떤 상태를 요청하며, 그 요청을 보내는 계정이 실제로 어디까지 할 수 있는가입니다. 문장을 고치기 전에 확인해야 했던 기본값은 그곳에 있었습니다.

이번 사고의 초안 원칙을 일상적인 글 작성 흐름으로 옮기려면 AI 초안 작성과 발행 판단을 분리하는 가이드를 함께 볼 수 있습니다. 작성 완료 보고와 공개 승인을 별도로 두는 기준으로 이어집니다.


사례 기준일: 2026-04-25. 당시 사고와 조치 기록을 2026-09-03에 재구성했습니다. 원문에서 확인된 수정과 이 글이 제안하는 추가 통제를 구분했습니다.

편집 보완: 2026-09-10. 당시 경험과 기록은 유지하고 읽기 흐름과 판단 기준을 보강했습니다. 이번 편집을 위해 새로운 실행·측정·복구 시험을 수행하지 않았습니다.

CONTENTS