Discord DM으로 Claude Code를 제어할 수 있지만, 신뢰 경계(Trust Boundary)를 명시적으로 설정해야만 가능합니다
요약
Claude Code를 Discord DM으로 제어할 수 있도록 지원하는 비공식 Linux 패처인 'Claude Code Trusted Discord'를 소개합니다. 보안을 위해 특정 Discord 계정의 DM만 신뢰할 수 있는 입력으로 처리하도록 설계되었습니다.
핵심 포인트
- Discord 메시지 수신 시 인증과 권한을 분리하여 보안 경계 설정
- 특정 Discord 계정 ID와 DM 채널 여부를 확인하는 이중 검증 적용
- 메타데이터를 메시지 텍스트가 아닌 Discord.js 객체에서 추출하여 안전성 확보
- 비공식 패처로서 로컬 파일의 민감한 정보(토큰, 키 등)를 수정하지 않음
공식 Claude Code Discord 채널은 의도적으로 보수적으로 운영됩니다. 발신자가 페어링(Paired)되거나 허용 목록(Allowlist)에 등록된 후에도, 일반적인 채널 메시지는 터미널에 직접 입력하는 텍스트와 구별할 수 없는 상태가 되는 대신 외부 채널 경계(External-channel boundary)를 통해 전달됩니다.
이러한 기본 설정은 합리적입니다. 인증(Authentication)은 이 Discord 메시지를 누가 보냈는가에 대한 답을 줄 뿐입니다. 이 메시지가 로컬 Claude Code 사용자와 동일한 권한을 가져야 하는가에 대한 답을 자동으로 제공하지는 않습니다.
저는 개인적인 설정을 위해 더 좁은 범위의 옵션을 원했습니다. 즉, 특정 Discord 계정의 다이렉트 메시지(DM)만 현재 활성화된 로컬 Claude Code 세션을 제어할 수 있게 하고, 그 외의 모든 발신자와 일반 길드(Guild) 메시지는 기존의 신뢰할 수 없는 경로(Untrusted path)에 그대로 두는 방식입니다.
저는 그 결과물을 공식 Discord 플러그인을 위한 비공식 Linux 패처인 Claude Code Trusted Discord로 출시했습니다.
이 패치는 의도적인 보안 경계(Security boundary)를 제거합니다. 설정된 Discord 계정을 제어할 수 있는 사람은 누구나 로컬에서 직접 타이핑하는 사람과 실질적으로 동일한 권한으로 대상 Claude Code 세션을 제어할 수 있습니다. 이는 Anthropic 또는 Discord와 관련이 없으며 그들의 승인을 받은 것도 아닙니다.
인증은 권한이 아닙니다
광범위한 구현은 위험할 정도로 쉬울 수 있습니다:
- Discord 메시지를 수신합니다.
- 발신자가 채널 허용 목록(Allowlist)을 통과했음을 인식합니다.
- 해당 텍스트를 신뢰할 수 있는 사용자 입력으로 주입(Inject)합니다.
세 번째 단계는 앞선 두 단계로부터 당연하게 도출되는 것이 아닙니다. 허용 목록에는 협업자, 테스트 계정 또는 향후 페어링될 계정들이 포함될 수 있습니다. 또한 길드 메시지는 개인 소유 채널과는 다른 사회적 및 보안적 맥락을 가집니다.
따라서 이 패치는 의도적으로 매우 좁은 두 번째 결정 경계(Decision boundary)를 추가합니다:
- 채널은 반드시 다이렉트 메시지(Direct message)여야 합니다.
- 발신자 ID(Sender ID)가 설정된 특정 숫자 형태의 Discord 계정 ID와 정확히 일치해야 합니다.
- 신뢰할 수 있는 전달(Trusted delivery)로 간주되기 전에 두 조건이 모두 충족되어야 합니다.
- 그 외의 모든 메시지는 기존의 상위 외부 채널(Upstream external-channel) 경로를 통해 계속 전달됩니다.
소유자 ID(Owner ID)는 플러그인 소스 내가 아닌, 0600 모드의 별도 파일에 저장됩니다. 설치 프로그램은 Discord 봇 토큰(Discord bot token), 페어링 허용 목록(pairing allowlist), Claude 데몬 제어 키(Claude daemon control key) 또는 세션 트랜스크립트(session transcripts)를 읽거나 수정하지 않습니다.
라우팅 메타데이터(Route metadata)는 메시지 텍스트에서 가져와서는 안 됩니다
신뢰할 수 있는 메시지는 세션이 올바른 Discord 대화를 통해 답변할 수 있도록 충분한 컨텍스트(Context)를 필요로 합니다. 해당 메타데이터는 사용자가 작성한 유사 봉투(pseudo-envelope) 형식이 아니라, Discord.js 객체로부터 가져와야 합니다.
브릿지(Bridge)는 인증된 채널 상태로부터 작은 로컬 페이로드(local payload)를 구축합니다:
- 소스(source): Discord;
- 다이렉트 메시지(direct-message) 채널 ID;
- Discord 메시지 ID;
- 인증된 작성자 ID(authenticated author ID);
- 플랫폼 타임스탬프(platform timestamp);
- 정제된 콘텐츠(sanitized content);
- 첨부 파일 참조(attachment references), 존재하는 경우.
일반적인 줄바꿈과 탭은 유지되지만, C0 및 C1 터미널 제어(terminal controls)는 제거됩니다. 더 중요한 점은, 메시지 내부의 텍스트가 자신의 송신자, 채널 또는 라우팅 식별자(routing identifiers)를 재정의할 수 없다는 것입니다.
이것은 프롬프트 인젝션(prompt injection)에 대한 일반적인 해결책은 아닙니다. 이는 인증된 소유자 메시지가 해당 프롬프트 주변에서 사용되는 전송 메타데이터(transport metadata)를 위조하는 것을 방지하기 위한 방법입니다.
놀라운 제약 사항: 세션은 반드시 백그라운드 데몬(background daemon)에 있어야 합니다
첫 번째 라이브 버전에는 오해를 불러일으킬 수 있는 실패 모드(failure mode)가 있었습니다. 신뢰할 수 있는 전달은 Claude Code의 로컬 데몬 제어 소켓(local daemon control socket)을 통해 작동했지만, 터미널에 직접 연결된 일반적인 포그라운드 세션(foreground session)은 데몬의 워커 명단(worker roster)에 존재하지 않았습니다.
다른 포그라운드 세션을 재시작하는 것도 도움이 되지 않았습니다. 응답할 데몬 워커가 없었기 때문입니다.
실제 전환 방법은 다음과 같습니다:
/background
또는 claude --bg 명령어로 세션을 실행하십시오.
해당 전환을 거치면, 정확한 세션이 Claude Code의 백그라운드 에이전트 명단(background-agent roster)에 나타나며 인증된 로컬 응답 작업(authenticated local reply operation)을 수신할 수 있습니다. 이후 claude agents 또는 claude attach를 사용하여 해당 세션에 연결할 수 있습니다.
버전 0.1.1에서는 플러그인의 세션 ID가 해당 명단(roster)에 존재하지 않을 경우, 명시적인 /background 안내와 함께 'fail closed(차단)' 상태가 됩니다. 이는 다른 워커(worker)를 추측하거나 임의의 터미널에 주입하지 않습니다.
프라이빗 인터페이스를 방어적으로 패치하기
이 프로젝트는 변경될 수 있는 두 가지 구현 세부 사항에 의존합니다:
- 공식 Discord 플러그인의 설치된 TypeScript 소스;
- Claude Code의 프라이빗 로컬 데몬 프로토콜 (private local daemon protocol).
이로 인해 소스 드리프트 (source drift)는 단순한 유지보수의 불편함이 아니라 보안 조건이 됩니다.
설치 프로그램은 정확한 소스 앵커 (source anchors)를 사용하며, 예상되는 구조가 없을 경우 패치를 거부합니다. 파일을 변경하기 전에 타임스탬프가 찍힌 형제 백업 (sibling backup) 파일을 생성합니다. 재설치는 멱등성 (idempotent)을 보장하며, --dry-run을 통해 변경될 내용을 확인할 수 있고, --uninstall은 식별 가능한 가장 최신의 깨끗한 백업을 복구합니다.
패치는 활성화된 설치된 플러그인 소스뿐만 아니라, 존재하는 경우 공식 마켓플레이스 체크아웃 (marketplace checkout)에도 적용됩니다. 그렇지 않으면 일상적인 플러그인 새로고침 과정에서 활성화된 패치가 수정되지 않은 복사본으로 조용히 교체될 수 있습니다.
테스트 스위트 (test suite)는 패치 멱등성, 드리프트 거부, 보호된 소유자 파일 권한, 백업 동작, 드라이 런 (dry runs), 삭제 (uninstall), 멀티 타겟 프리플라이트 (multi-target preflight), 그리고 백그라운드 세션 에러 경로를 다룹니다.
사용하지 말아야 할 경우
다음과 같은 경우에는 이 브릿지 (bridge)를 사용하지 마십시오:
- 한 명 이상의 사람이 신뢰할 수 있는 Discord 계정을 제어하는 경우;
- 봇이 DM 신원만으로는 충분한 경계가 되지 않는 공유 길드 (guild) 워크플로우에 참여하는 경우;
- 대상 Claude 세션이 해당 Discord 계정에 노출하고자 하는 것보다 더 넓은 파일 시스템 또는 서비스 액세스 권한을 가진 경우;
- 지원되는 안정적인 통합 계약 (integration contract)이 필요한 경우;
- Claude Code 또는 플러그인 업데이트 후 패치가 깨지는 것을 용납할 수 없는 경우.
대부분의 설정에서는 공식적인 신뢰할 수 없는 채널 (untrusted channel) 동작이 정답입니다.
이 패치는 Discord 계정을 의도적으로 원격 소유자 터미널 (remote owner terminal)로 취급하고, 해당 계정이 적절히 보호되며, 운영자가 업스트림 (upstream) 변경 후 패치를 다시 감사(audit)할 의사가 있는 더 좁은 사례를 위한 것입니다.
먼저 dry run으로 시도해 보세요
해당 저장소(repository)에는 설치, 삭제, 호환성 및 위협 모델(threat-model)에 관한 참고 사항이 포함되어 있습니다:
생성된 패치(patch)를 읽고 --dry-run 옵션과 함께 설치 프로그램을 실행하는 것으로 시작하세요. 신뢰할 수 있는 원격 제어 경로(trusted remote control path)는 채널 경계를 우회하는 숨겨진 지름길이 아니라, 사용자가 검사(inspect), 비활성화(disable) 및 복구(restore)할 수 있는 것이어야 합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기