AI 에이전트 두 대를 돌렸더니 에릭이 올리버가 됐다

에릭한테 말을 걸었는데 올리버가 대답했다.

에릭은 AI 관련 리서치와 블로그, SNS 운영을 맡긴 AI 에이전트다. 올리버는 업무용으로 따로 구성하고 싶었다. 둘 다 디스코드로 연결해서 쓰고자 했다. 계정을 따로 만들었고 작업 폴더도 갈라뒀다. 당연히 분리돼 있다고 믿었다. 그런데 에릭을 부른 자리에 올리버가 나타났다.

그날 몇 시간을 이것만 붙잡고 있었다. 하나를 살리면 다른 하나가 죽어 있었다. 답이 안 오길래 죽은 줄 알고 계속 재시작했다. 나중에 보니 그 재시작이 문제를 키우고 있었다.

원인은 접속 토큰이 놓인 자리였다. AI 에이전트를 돌리는 프로그램은 디스코드에 로그인할 때 쓰는 열쇠 문자열, 즉 접속 토큰을 파일로 저장해둔다. 그 파일이 놓이는 자리를 설정 폴더라고 한다. 프로그램은 켜질 때마다 이 폴더를 열어 토큰을 꺼내 쓴다.

두 에이전트가 같은 설정 폴더를 쓰고 있었다. 계정을 나누고 작업 폴더도 갈랐는데, 정작 토큰이 놓인 자리는 하나였다. 그래서 둘이 같은 열쇠를 집어 들었다.

30초 요약
  • 계정과 작업 폴더는 갈랐는데 설정 폴더는 하나였다. 분리했다고 믿은 것과 실제로 분리된 것이 달랐다.
  • 증상은 셋인데 뿌리는 하나였다. 답이 새고, 한쪽이 꺼지고, 이름표가 바뀐 게 전부 같은 원인에서 나왔다.
  • 범인은 설정하지 않은 값이었다. 설정 폴더를 안 정하면 미리 정해진 기본 설정 폴더가 쓰인다. 그 기본값이 전부에 적용됐다.
  • 해결의 핵심은 기본 설정 폴더를 비운 것이다. 실수를 막는 대신, 실수하면 조용히 넘어가지 않고 바로 멈추게 만들었다.

하나를 살리면 하나가 죽어 있었다

고장은 세 갈래로 왔다. 처음엔 셋 다 서로 다른 문제처럼 보였고, 그래서 각각 따로 고치려 들었다. 그게 시간을 잡아먹었다.

메신저 대화창에서 AI 에이전트 에릭과 주고받은 메시지 화면
평소에는 이렇게 메신저로 말을 걸어 쓴다.

시작은 답이 새는 거였다. 말을 걸면 답이 오다 말거나 아예 안 왔다. 반응이 없으니 에이전트가 죽은 줄 알고 껐다 켰다. 그렇게 몇 번을 반복했다.

그러다 시소가 시작됐다. 에릭을 살려놓고 올리버를 확인하면 올리버가 꺼져 있었다. 올리버를 다시 띄우면 이번엔 에릭이 없었다. 둘이 번갈아 죽는데 이유를 알 수가 없었다. 새벽에 자동 재시작이 돌고 난 직후면 특히 자주 터졌다.

이름표가 바뀐 건 그다음이었다. 에릭한테 시킨 일을 올리버가 받아 갔다. 내가 헛본 게 아니었다. 설정 파일에 남은 기록에 업무용 에이전트가 개인용 에이전트의 토큰으로 로그인했다는 내용이 그대로 적혀 있었다.

에릭에게 확인하려고 “너 누구야?” 라고 물어보니 올리버라고 대답했다.

답이 왜 오다 말았을까

같은 토큰으로 여러 개의 연결이 동시에 붙어 있었기 때문이다. 디스코드 쪽에서 보면 같은 이름표를 단 접속이 여럿이니, 메시지를 그 접속들에 나눠서 보낸다. 절반은 엉뚱한 쪽으로 갔고, 그쪽은 아무 맥락도 없이 허공에 답하고 있었다.

디스코드 개발 문서도 이 구조를 그대로 설명한다. 하나의 앱이 여러 연결을 열면 이벤트를 그 연결들에 나눠 보낸다고 돼 있다. 원래는 규모가 큰 봇이 부하를 나누라고 만들어둔 장치다. 내 경우엔 의도치 않게 그 상태가 됐다.

우편함 하나에 같은 명찰을 단 사람이 여럿 서 있는 장면을 떠올리면 쉽다. 편지는 도착하는데, 매번 누가 집어갈지 알 수 없다. 내가 기다리던 사람이 집어갈 확률은 절반쯤이었다.

한쪽을 켜면 왜 다른 쪽이 꺼졌을까

에이전트가 죽으면 되살리라고 붙여둔 워치독이 남의 에이전트까지 정리해버렸기 때문이다. 워치독은 프로세스가 살아 있는지 주기적으로 확인하고 없으면 다시 띄우는 감시용 스크립트다. 두 에이전트를 실행하는 명령문이 글자 하나까지 똑같았고, 워치독은 이름과 명령문만 보고 판단했다. 남의 담당을 알아볼 방법이 없었다.

건물 당직 근무자 둘이 같은 제복을 입은 사람을 각자 자기 담당이라고 여기는 상황과 같다. 한쪽이 정리에 나서면 상대 담당까지 같이 끌려 나간다. 매일 새벽 4시에 둘 다 자동으로 재시작하게 해둔 것도 화근이었다. 같은 순간에 깨어나 서로를 밟았다.

셋 다 다른 고장처럼 보였지만 뿌리는 하나였다.

진짜 범인은 설정하지 않은 값이었다

설정 폴더 위치를 따로 정해주지 않으면 프로그램은 미리 정해진 기본 설정 폴더를 쓴다. 이 위치는 환경변수 하나로 정한다. 내가 쓰는 도구에서는 DISCORD_STATE_DIR이라는 이름이었다. 도구마다 이름은 다르지만 로그인 정보를 어디에 둘지 지정하는 값은 대부분 있다. 개인용 에이전트인 에릭이 바로 그 기본 설정 폴더를 쓰고 있었다.

문제는 그다음이다. 이 컴퓨터에서 새로 뜨는 프로그램은 설정 폴더를 따로 지정하지 않으면 전부 그 기본 설정 폴더로 몰렸다. 프로젝트를 하나 새로 열 때마다 에릭의 토큰을 집어 든 정체불명의 접속이 하나씩 늘었다.

설정 폴더를 지정하지 않은 모든 접속이 한곳으로 몰렸다
에릭
새 프로젝트
또 다른 창
올리버
▼ 전부 같은 곳을 연다 ▼
기본 설정 폴더 · 에릭의 접속 토큰 1개
먼저 여는 쪽이 집어 든다

숫자로도 드러났다. 24시간 로그인 시도가 에릭 30회 (2026년 8월 직접 측정), 올리버 7회 (같은 기간)였다. 올리버의 7회는 정상 재시작 횟수와 딱 떨어졌다. 에릭 쪽은 스물세 번이 설명되지 않았다.

24시간 로그인 시도 횟수
에릭 (개인용) 30회
올리버 (업무용) 7회
올리버의 7회는 정상 재시작 횟수와 일치했다. 에릭의 23회분이 설명되지 않았다.

이런 종류의 사고가 나만의 불운은 아니다. 웹 보안 표준을 만드는 국제 비영리 단체 OWASP는 설정 오류를 주요 보안 위험 5위로 꼽는다. 검사한 애플리케이션 중 어떤 형태로든 설정 문제가 나온 비율이 90% (OWASP Top 10 A05:2021)였다. 이때 지목한 대표 원인이 “안전하지 않은 기본 설정”이다. 손대지 않고 그냥 둔 값이 사고의 출발점이 된다는 얘기다.

겉으로 보인 증상 내가 의심한 것 실제 원인
답이 오다 말았다 에이전트가 죽었다 같은 토큰을 쓴 접속이 여럿이라 메시지가 갈렸다
한쪽을 켜면 한쪽이 꺼졌다 메모리가 부족하다 워치독이 남의 에이전트까지 정리했다
에릭이 올리버가 됐다 설정을 잘못 넣었다 설정 폴더를 아예 안 정해서 기본값이 공유됐다

헛짚은 것 세 가지

오래 걸린 이유는 엉뚱한 곳을 세 번 팠기 때문이다. 셋 다 그럴듯해 보였고, 그래서 의심을 안 했다.

처음엔 에이전트가 죽은 줄 알았다. 확인해보니 안 보였을 뿐 다른 쪽에서 멀쩡히 돌고 있었다. 보는 방법이 달랐던 건데 나는 상태가 잘못됐다고 판단했다. 확인 방법이 틀리면 멀쩡한 것도 고장으로 보인다.

두 번째로 판 곳은 설정이었다. 값을 분명히 지정했는데 실행 시점에는 사라져 있었다. 지정한 값이 실행 환경까지 따라가는 구조가 아니었다. 고쳤다고 생각한 게 사실은 안 고쳐진 상태였다.

가장 뼈아픈 건 세 번째다. 문제를 자동으로 잡아주려고 점검 스크립트를 만들었는데, 그게 “문제 있음” 두 건을 보고했다. 하나씩 손으로 확인해보니 둘 다 오탐이었다. 점검 도구가 특정 프로세스를 못 읽고 있었다. 문제를 찾는 도구도 틀릴 수 있다는 걸 그때 알았다.

무엇을 어떻게 갈랐나

설정 폴더를 완전히 나누는 것부터 했다. 각 에이전트에게 자기 설정 폴더를 하나씩 콕 집어 지정했다. 안 정해도 알아서 되겠지, 하는 기대를 버렸다.

진짜 효과를 본 건 그다음 조치다. 기본 설정 폴더를 아예 비웠다. 토큰이 없으면 프로그램은 스스로 종료된다. 설정 폴더를 지정하지 않은 접속은 이제 시작조차 못 한다. 실수를 막는 게 아니라, 실수해도 조용히 넘어가지 않고 바로 멈추게 만든 쪽에 가깝다.

이건 내가 발명한 요령이 아니라 보안 설계의 오래된 원칙이다. 1974년 고전 논문에서 Saltzer와 Schroeder가 쓴 원칙이다. 접근 결정은 배제가 아니라 허가에 근거해야 한다. 기본 상태를 접근 불가로 두고, 허용할 조건만 따로 밝힌다. 반세기 전 원칙인데 내 책상 위 문제에 그대로 들어맞았다.

나머지 둘은 부수 정리에 가깝다. 워치독이 이름이나 명령문이 아니라 어느 폴더에서 돌고 있는지로 담당을 구분하게 바꿨다. 두 폴더는 절대 겹치지 않으니 오인할 여지가 없다. 그리고 새벽 자동 재시작 시각을 10분 어긋나게 뒀다. 같은 순간에 깨어날 이유가 없어서 그냥 떼놨다.

디스코드가 정해둔 로그인 시도 한도는 24시간에 1,000회 (Discord 개발자 문서)다. 넘기면 모든 세션을 끊고 토큰 자체를 초기화한다고 돼 있다. 내 서른 번은 한도 근처에도 못 갔다. 다만 정체불명 접속이 계속 늘어나는 구조였다면 언젠가 닿았을 숫자다.

정리

분리했다고 믿은 것과 실제로 분리된 것은 달랐다. 계정을 나누고 폴더를 갈랐으니 됐다고 생각했다. 정작 아무도 안 보는 자리에서 설정 폴더 하나가 공유되고 있었다.

자동화를 붙여 쓸수록 눈에 보이는 설정은 오히려 안전하다. 내가 적어 넣은 값은 언제든 다시 읽어볼 수 있으니까. 위험한 쪽은 내가 적지 않아서 어딘가에서 알아서 채워진 값이다. 화면에 나타나지 않는데 새로 여는 모든 것에 조용히 적용된다. AI 에이전트든 자동화 스크립트든 두 개 이상을 같이 돌린다면 순서를 바꿔보는 게 빠르다. “무엇을 설정했나”보다 “무엇을 설정하지 않았나”를 먼저 센다. 나도 디스코드로 부리는 개인 에이전트를 만들면서 계정과 폴더까지는 챙겼다. 그 아래 깔린 기본값은 한 번도 들여다본 적이 없었다.

고칠 때도 순서가 있었다. 잘못된 접속을 막는 것보다, 잘못된 접속이 조용히 성공하지 못하게 만드는 쪽이 확실했다. 점검 도구조차 두 번 틀린 답을 줬다. 도구의 판정도 한 번은 손으로 확인하는 게 맞다.

그리고 아직 안 끝났다. 로그인 시도 횟수는 지금도 높게 찍힌다. 고치기 이전 24시간이 집계에 남아서일 가능성이 크지만 확정은 아니다. 하루 뒤 다시 재봐야 갈린다. 이런 문제는 “고쳤다”가 아니라 “고쳐진 것 같다, 내일 확인한다”가 정직한 상태다. 내일 숫자가 안 떨어지면 아직 못 찾은 접속이 어딘가에 하나 더 있다는 뜻이 된다.


참고 자료

함께 읽으면 좋은 글

Discord로 만든 AI 에이전트 에릭Discord로 만든 AI 에이전트 ‘에릭’, 대화만 하면 알아서 일이 끝난다이번 글에 나온 에릭을 어떻게 만들어 쓰고 있는지 정리한 글.

어바웃코어랩
어바웃코어랩

현직 AI 프로덕트 매니저. AI 도구를 일상과 업무에 녹이는 실험을 계속하며, 모든 글은 직접 테스트한 결과를 바탕으로 작성합니다. 부가적인 일은 AI에게, 우리는 일상의 본질에.

기사 : 138