요약
텍스트 명령 !<word>가 text_commands.rs의 match에 없으면 Ok(false)로 돌아오고, intake_gate.rs의 ! 접두 셸 단축 경로가 그 문자열을 그대로 handle_shell_command_raw(router/message_handler/control.rs)에 넘겨 셸로 실행한다. 이 핸들러에는 owner·고위험 옵트인 검사가 없다. 결과: !shell(CommandRisk::HighRisk, owner + AGENTDESK_DISCORD_HIGH_RISK_ENABLED 필요)이 !ls -la 한 줄로 우회된다.
근거 (2026-09-05 main 3b3b961)
src/services/discord/commands/command_policy.rs:32 — 미등록 명령 기본 등급 _ => CommandRisk::Mutating (고위험 아님 → owner 가드 미발동)
src/services/discord/commands/command_policy.rs:23 — !shell은 HighRisk
src/services/discord/commands/text_commands.rs:150-172 — 고위험일 때만 owner/env 검사
src/services/discord/commands/text_commands.rs:1480 — _ => {} → Ok(false)
src/services/discord/router/intake_gate.rs:1559-1571 — text.starts_with('!') → handle_shell_command_raw
src/services/discord/router/message_handler/control.rs:3-40 — 인증 검사 없이 shell_command_builder(cmd).spawn()
- 선행 인증은
intake_gate.rs:736 check_auth(allowed_user_ids / allow_all_users)뿐. 라이브 yaml에는 allow_all_users: true인 채널 바인딩이 존재한다.
부수 결함 (같은 뿌리)
command_policy.rs:67이 !usage !receipt !sessions 등 8개에 등급을 매겼지만 text_commands.rs에 해당 arm이 없어 전부 이 경로로 새어 셸 명령 usage/receipt를 실행하려 든다(정책표와 핸들러표 이중 진실).
수정 방향
- 셸 단축 경로를 명시적
!shell <cmd>(또는 별도 접두)로만 진입하게 하고, 미등록 !<word>는 "알 수 없는 명령" 응답으로 끝낸다. 하위 호환이 필요하면 !<word>의 셸 해석을 HighRisk로 분류해 동일 게이트를 태운다(_ => CommandRisk::HighRisk가 최소 변경).
handle_shell_command_raw 자체에 owner/옵트인 검사를 넣어 호출 경로와 무관하게 fail-closed.
command_policy의 등급표를 text_commands 핸들러 목록에서 파생시키거나(단일 진실), 등급만 있고 핸들러 없는 항목을 컴파일 타임/테스트로 실패시킨다.
- 회귀 테스트: 비-owner 인증 사용자가
!ls 전송 → 셸 미실행·거부 응답; !usage → 셸 미실행.
관련
요약
텍스트 명령
!<word>가text_commands.rs의 match에 없으면Ok(false)로 돌아오고,intake_gate.rs의!접두 셸 단축 경로가 그 문자열을 그대로handle_shell_command_raw(router/message_handler/control.rs)에 넘겨 셸로 실행한다. 이 핸들러에는 owner·고위험 옵트인 검사가 없다. 결과:!shell(CommandRisk::HighRisk, owner +AGENTDESK_DISCORD_HIGH_RISK_ENABLED필요)이!ls -la한 줄로 우회된다.근거 (2026-09-05 main 3b3b961)
src/services/discord/commands/command_policy.rs:32— 미등록 명령 기본 등급_ => CommandRisk::Mutating(고위험 아님 → owner 가드 미발동)src/services/discord/commands/command_policy.rs:23—!shell은 HighRisksrc/services/discord/commands/text_commands.rs:150-172— 고위험일 때만 owner/env 검사src/services/discord/commands/text_commands.rs:1480—_ => {}→Ok(false)src/services/discord/router/intake_gate.rs:1559-1571—text.starts_with('!')→handle_shell_command_rawsrc/services/discord/router/message_handler/control.rs:3-40— 인증 검사 없이shell_command_builder(cmd).spawn()intake_gate.rs:736check_auth(allowed_user_ids / allow_all_users)뿐. 라이브 yaml에는allow_all_users: true인 채널 바인딩이 존재한다.부수 결함 (같은 뿌리)
command_policy.rs:67이!usage!receipt!sessions등 8개에 등급을 매겼지만text_commands.rs에 해당 arm이 없어 전부 이 경로로 새어 셸 명령usage/receipt를 실행하려 든다(정책표와 핸들러표 이중 진실).수정 방향
!shell <cmd>(또는 별도 접두)로만 진입하게 하고, 미등록!<word>는 "알 수 없는 명령" 응답으로 끝낸다. 하위 호환이 필요하면!<word>의 셸 해석을 HighRisk로 분류해 동일 게이트를 태운다(_ => CommandRisk::HighRisk가 최소 변경).handle_shell_command_raw자체에 owner/옵트인 검사를 넣어 호출 경로와 무관하게 fail-closed.command_policy의 등급표를text_commands핸들러 목록에서 파생시키거나(단일 진실), 등급만 있고 핸들러 없는 항목을 컴파일 타임/테스트로 실패시킨다.!ls전송 → 셸 미실행·거부 응답;!usage→ 셸 미실행.관련