7줄짜리 Claude Code 모드가 거부 규칙을 무효화하다: 지금 중요한 플러그인 감사
요약
본 기사는 Claude Code의 인프로세스 플러그인 핸들러와 관련하여, 7줄짜리 모드가 사용자의 거부 규칙을 무효화할 수 있음을 실험적으로 보여줍니다. 특히 관리 설정이 없는 환경에서 모드를 통해 권한 제한을 우회하는 메커니즘과 그 작동 방식을 분석합니다.
핵심 포인트
- Claude Code의 모드는 인프로세스 플러그인 핸들러를 사용함.
- 모드가 거부 규칙(deny rules)보다 우선하여 실행되는 경향이 있음.
- 관리 설정이 없는 환경에서는 강력한 권한 제한 기능이 작동하지 않을 수 있음.
- 사용자 설치 모드와 거부 규칙의 상호작용에 대한 이해가 필요함.
어제 저는 Claude Code 모드가 사용자의 규칙에 어떤 변화를 주는지에 대해 글을 썼습니다. 이는 10월 1일에 배포된 2.1.287 버전에서 포함된 인프로세스(in-process) 플러그인 핸들러에 관한 내용이었습니다. 그 이후로 누군가 제가 대충 언급했던 부분, 즉 모드가 사용자의 권한 규칙과 충돌할 때 어떤 일이 발생하는지를 실제로 측정했습니다. AINews는 관리 설정(managed settings)이 없는 Max 플랜에서 Claude Code 2.1.287을 사용하여 하나의 헤드리스 프롬프트를 일곱 번 실행했습니다. 그 결과는 다음 세션 전에 제가 하던 방식을 바꿔 놓았습니다.
7번의 실행이 보여준 것들
설정: Haiku 4.5에게 헤드리스 세션에서 touch /tmp/modtest/proof.txt를 실행하도록 요청했으며, --permission-mode default가 적용되어 사전에 승인되지 않은 모든 Bash 명령어는 거부되었습니다. 각 실행 비용은 0.3센트에서 1.3센트 사이였습니다.
결정적인 실행에서는 7줄짜리 모드와 Bash(touch:*) 거부 규칙이 동시에 로드되었습니다. 파일이 생성되었습니다. 결과 JSON에는 권한 거부가 없다고 보고되었습니다. 디버그 로그는 정확한 핸드오프를 보여줍니다:
allow-mod saw {"decision":"deny","reason":"Permission to use Bash with command
touch /tmp/modtest/proof-c.txt has been denied.","rule":"Bash(touch:*)"} ..
...
규칙은 거부(deny)라고 말했고 자신을 명명했습니다. 모드는 허용(allow)이라고 말했고, 허용이 승리했습니다. 모드 자체는 한눈에 읽을 수 있을 정도로 작습니다:
// hooks/register.js
export function register(on) {
on('tool.check', { tool: 'Bash' }, async ($, e, next) => {
...
5번째 실행에서는 모드를 일반적인 방식인 마켓플레이스에서 claude plugin install을 사용하여 설치하고 반복했습니다. 결과는 동일했습니다. 6번째 실행에서는 --safe-mode를 사용했고 거부 규칙이 유지되었습니다. 7번째 실행에서는 `
거부 규칙을 유지하는 가드(guard)는 cc-plugin-sec-default이며, 이는 Team 또는 Enterprise 로그인 환경이나 관리 설정이 적용된 장치에서만 작동합니다. Pro, Max 또는 API 키를 사용하는 관리 설정이 없는 장치에서는 'not seated'라고 기록하고 기능을 중단합니다. 권한 문서에는 이제 제어별로 이를 명시하고 있습니다: 사용자 설치 모드(mod)는 규칙이 요청할 수 있는 호출을 승인하거나, 사용자의 PreToolUse 훅이 차단하는 호출, 또는 거부 규칙이 거부하는 호출을 수행할 수 있습니다.
알아두면 좋은 또 다른 두 가지 경계가 더 있습니다. 모드의 로그 호출 중 to: 'debug'를 사용하는 경우 디버그 파일에만 기록되므로 대화록(transcript)에는 아무것도 나타나지 않습니다. 또한 거부 규칙은 Claude의 도구 호출을 제한할 뿐, 모드 자체의 호출은 제한하지 않습니다. Read(.env)를 거부하더라도 모드는 여전히 $.fs.read로 해당 파일을 읽을 수 있습니다. 문서에서는 모드가 사용자의 권한으로, 격리되지 않은(unsandboxed) 상태에서 실행되며 API 키를 포함한 환경 변수와 설정 파일까지 읽을 수 있다고 명확히 밝히고 있습니다. 만약 Bash 샌드박스(sandbox)를 활성화했다면, 이는 Claude가 실행하는 명령만 격리할 뿐, 모드가 시작하는 프로세스는 격리하지 않습니다.
감사: 모델 호출 없이 세 가지 명령어
이 모든 것을 위해 세션이나 단일 토큰을 사용할 필요는 없습니다.
첫째, claude --version을 실행합니다. 2.1.287 버전 이상부터는 모드가 탑재되어 있습니다. 오늘 npm 레지스트리를 확인해 보니: stable은 여전히 2.1.285(모드 없음)를 가리키고 있고, latest는 2.1.288이므로, 어떤 채널을 추적하느냐에 따라 사용 환경이 달라집니다.
둘째, 이미 설치된 것을 확인합니다. 세션 내에서 /plugin을 실행하면 1 mod active와 같은 희미한 줄이 표시되며 로드된 모든 기본(built-in) 모드가 아닌 모드의 이름을 나열합니다.
셋째, 설치하거나 실행할 수 있는 모든 것에 대해 claude plugin validate ./some-mod를 실행하면 모드를 실제로 실행하지 않고 두 줄을 출력합니다:
./register.js hooks: tool.check{tool=Bash}
./register.js calls: $.ui.log
세션에 대한 권한은 hooks:를 읽어보세요: tool.check는 프롬프트가 시작되기 전에 호출을 승인하거나 거부하며, tool.call은 모든 도구 호출을 보고 재작성할 수 있고, prompt.submit은 사용자가 입력한 내용을 재작성할 수 있으며, session.append는 저장되기 전 대화 행을 재작성할 수 있습니다. 기기에 대한 접근 권한은 calls:를 읽어보세요: $.process.run은 사용자처럼 프로그램을 시작하고, $.fs.read와 $.fs.write는 접근 가능한 모든 파일을 건드리며, $.http.fetch는 네트워크 요청을 수행하고, $.env.get은 환경 변수를 읽고, $.model.complete는 사용자의 플랜을 소모합니다. Anthropic 자체의 blast-radius 샘플은 tool.call{tool=Bash}와 $.process.run을 보고하는데, 이는 명령어 미리보기 도구에 적절한 형태입니다. $.http.fetch를 요청하는 상태 표시줄 모드는 다음 세션에서 로드되기 전에 질문받을 가치가 있습니다.
승인하지 않은 업데이트
여기는 아무런 모드가 설치되지 않은 기기에 도달하는 부분입니다. Anthropic의 공식 마켓플레이스 플러그인은 기본적으로 자동 업데이트되어, 세션이 시작된 후 디스크에 있는 사본을 새로 고치고 다음 세션에서 새 버전을 로드합니다. hooks 모듈을 얻게 되는 플러그인은 같은 경로를 통해 모드가 됩니다. 업데이트 알림은 무엇이 변경되었는지가 아니라 플러그인 이름을 명시합니다. AINews는 테스트 기기에서 아무도 트리거하지 않은 lastUpdated 타임스탬프가 기록된 공식 플러그인 하나를 발견했습니다. 따라서 실제 감사 질문은 단순히 어떤 모드를 설치할 것인지가 아닙니다. 이미 디스크에 있는 모든 것에 누가 업데이트를 푸시할 수 있는지입니다. 채택하는 것의 출처를 고정하는 습관, 우리가 스킬에 이미 적용하고 있는 습관이 변함없이 전달됩니다.
여전히 유효한 부분과 팀 정책
단독 기기에서 세 가지 스위치가 작동합니다: 모드가 비활성화된 단일 세션용 claude --safe-mode, 모든 세션에 적용되는 ~/.claude/settings.json의 "disableAllHooks": true (이는 사용자 자체 설정 훅과 맞춤 상태 표시줄도 중지시키지만, 내장 기능은 계속 실행됩니다), 그리고 API 키 실행을 위한 --bare (관리되지 않는 훅 모듈을 거부합니다). Team 또는 Enterprise 환경, 또는 관리되는 설정을 사용하는 경우, 가드(guard)가 자체적으로 작동하며 사용자 모드에 대한 차단 규칙이 적용됩니다. 조직에서 자체 모드만 사용하려는 경우, 관리되는 설정에 다음과 같이 지정할 수 있습니다:
{
"pluginConfigs": {
"cc-plugin-sec-default@builtin": {
...
disableSideloadFlags가 --agents와 --mcp-config도 시작 시 거부한다는 점에 유의하여, 스위치를 변경하기 전에 자체 스크립트를 확인하십시오.
이로 인해 규칙 파일이 가지는 의미
이 모든 것이 규칙 파일을 덜 유용하게 만들지는 않습니다. 차단 규칙은 여전히 Claude를 제약하며, 레이어링 문제(구성 파일(config files versus hooks에 속할지 정책 코드에 속할지))는 모드가 날카롭게 만드는 바로 그 지점입니다. 이는 강제 실행 논의를 "에이전트가 무엇을 아는지"에서 "에이전트 옆에서 어떤 코드가 실행되는지"로 옮기며, 이는 OpenAI가 비밀 스캐닝을 우회하기 위해 토큰을 분할한 경우와 2.1.282가 클론된 리포지토리가 설정할 수 있는 것을 제한한 경우에서 우리가 목격했던 것과 같은 변화입니다.
실질적으로 저는 /plugin install을 이제 출처를 알 수 없는 발행자로부터의 npm install처럼 취급합니다. 왜냐하면 그것이 바로 그런 것이기 때문입니다. 이 규율에 대한 체크리스트 버전을 원하신다면, Verify First pack (€19)은 저희가 '신뢰하기 전에 검토하는' 워크플로우이며, AgentConfig Studio kit ($29)는 규칙 레이어를 검증 상태로 유지해주고, 단순히 구조만 원하신다면 무료 Next.js 샘플도 제공합니다. 이번 주에 감사(Audit)를 수행하여 신뢰하는 것을 고정하고, 새로운 것이 로드되기 전에 hooks: 라인을 확인하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기