보안 정책
opsgate는 원격 HTTP, 인증, 사람이 승인한 쓰기 기능을 제공하는 공개된 0.7.x 프로젝트입니다. 선택 사항인 note provider는 아직 실험 단계입니다. 외부 보안 검토는 아직 받지 않았으므로, 배포할 구현을 직접 검토하세요.
위협 모델
opsgate 인스턴스 하나는 신뢰 그룹 하나입니다. ops:read는 활성화된 모든 읽기 provider에서 서버, 클러스터 리소스, 노트를 읽을 수 있는 권한입니다. provider 허용 목록으로 리소스를 제한하고, server.tools와 사용자별/토큰별 tools glob으로 도구 접근 범위를 줄일 수 있습니다. 하지만 이런 설정이 자격 증명이나 프로세스를 분리하지는 않습니다. 신뢰 수준이 다르면 인스턴스와 계정을 분리하세요. 예를 들어 프로덕션 운영과 개인 노트를 각각 분리하세요. 각 인스턴스의 자격 증명과 접근 가능한 데이터는 신뢰 그룹 전체가 사용해도 되는 범위로 제한하세요.
opsgate가 제공하는 보안 경계는 읽기 도구와 명시적으로 승인한 쓰기 작업만 허용하는 제한된 MCP 인터페이스입니다. provider를 명시적으로 활성화해야 하며, 네임스페이스 허용 목록, 네임스페이스 거부 목록, 스코프 검사, 호출 및 출력 제한, 마스킹, 호출별 감사 로그를 적용합니다. 마스킹이 모든 비밀값을 가린다고 보장하지는 않습니다. 임의의 셸이나 exec 인터페이스는 제공하지 않습니다. Kubernetes 시크릿은 제외하고 ConfigMap 값은 기본적으로 숨깁니다. 이런 통제 장치는 실수로 정보가 새는 일을 줄이고, 클라이언트가 opsgate에 요청할 수 있는 작업을 제한합니다.
이런 통제 장치가 있어도 신뢰할 수 없는 출력이 안전해지지는 않습니다. 로그, 이벤트, 애너테이션, 리소스 이름에는 프롬프트 인젝션이 포함될 수 있으므로, 출력은 지시가 아닌 데이터로 취급하세요. 악의적이거나 침해된 클라이언트는 설정된 스코프와 허용 목록 안에서 모든 작업을 요청할 수 있습니다. 반환된 데이터를 복사하거나 연결된 다른 도구를 공격할 수도 있습니다. MCP 애너테이션은 힌트일 뿐, 권한을 허용하는 근거가 아닙니다. stdio는 서버를 실행하는 OS 계정을 신뢰하며, 설정된 사용자 이름은 레이블일 뿐입니다.
RBAC이나 kubeconfig 권한이 지나치게 넓으면 버그나 침해가 일어났을 때 피해도 커집니다. 필요한 읽기 권한과, 쓰기를 사용할 경우 필요한 쓰기 권한만 가진 전용 자격 증명을 사용하세요. 함께 제공하는 RBAC 매니페스트도 검토하세요. kubeconfig의 exec 및 auth-provider 자격 증명 플러그인은 거부합니다. kubeconfig 파일과 설정 경로는 신뢰할 수 있는 소유자가 관리해야 합니다. 네임스페이스 허용/거부 규칙은 네임스페이스 범위 리소스와 Namespace 객체를 이름으로 필터링합니다. Nodes나 PersistentVolumes는 제한하지 않으며, k8s_overview의 노드도 마찬가지입니다. 클러스터 범위 리소스 종류에는 namespace를 생략하세요. 함께 제공하는 ClusterRoleBinding은 클러스터 전체의 읽기를 허용하므로, 가능하면 네임스페이스 RoleBinding을 사용하세요. provider와 그 자격 증명을 공격자가 제어할 수 없어야 합니다. root 실행은 권장하지 않습니다. 필요한 클러스터 접근 권한만 가진 일반 계정으로 실행하세요.
마스킹에 사용하는 텍스트 패턴과 객체에서 민감한 값을 제거하는 방식은 도구 참조에서 설명합니다. 작업 로그 페이지, 노트를 줄 단위로 나눈 페이지, 검색 스니펫은 크기 제한 안의 전체 원문에서 민감한 부분을 찾아 마스킹합니다. 따라서 페이지 경계에 걸친 비밀값도 가립니다. 일부만 출력할 때도 마스킹한 부분의 줄바꿈은 유지합니다. 개인 키 PEM 블록에 BEGIN 또는 END 마커가 빠져 있으면, 확인할 수 있는 원문의 시작부터 또는 끝까지 마스킹합니다. 두 마커가 모두 없으면 PEM으로 식별할 수 없습니다. ConfigMap의 data 및 binaryData 값은 기본적으로 숨깁니다. 파드와 워크로드의 리터럴 환경 변수는 이름에 pass, secret, token, key, credential, auth, dsn, private, cert, database_url이 포함되면 값을 마스킹하며, 대소문자는 구분하지 않습니다. 다른 값은 그대로 보일 수 있습니다. valueFrom 참조는 그대로 보여 주며 실제 값을 조회하지 않습니다.
마스킹은 안전장치일 뿐, 비밀값이 새지 않는다고 보장하지 않습니다. 로그, 메타데이터, 프로세스 정보에는 예상하지 못한 형식의 자격 증명이 포함될 수 있으므로, 처음부터 비밀값을 수집하지 않도록 하세요. 감사 로그도 인자와 오류에 민감한 정보가 남을 수 있으므로 보호하세요. 감사 로그는 변조를 막는 원장이 아니며, 쓰기에 실패하면 기록을 유실 없이 전달한다고 보장하지 않습니다. 컨텍스트의 제한 시간은 핸들러와 의존 구성 요소가 취소 신호를 따를 때 적용됩니다. 출력 제한도 리소스 고갈 위험을 모두 없애지는 않습니다.
opsgate는 호스트, 커널, 서버 바이너리, 의존성, 관리자, 자격 증명 저장소가 침해된 상황을 방어하지 않습니다. 클라이언트를 샌드박스에 격리하거나 서버를 실행한 사용자의 권한을 회수하지도 않습니다. 도난당한 Bearer 토큰을 유효 기간 안에 사용하는 행위, 네트워크 경계에서 발생하는 서비스 거부, 인가된 클라이언트의 정보 유출도 막지 못합니다.
원격 노출과 인가
HTTP는 Protected Resource Metadata와 함께 /mcp를 제공합니다. 인증은 필수이며, 루프백 개발 환경을 제외하면 공개 origin에 HTTPS가 필요합니다. 신뢰할 수 있는 프록시에서 TLS를 종료하고 백엔드는 비공개로 유지하세요. 배포에 설명된 discovery, OAuth, 승인 경로를 전달하세요. Bearer 토큰, 쿠키, 인가 코드, 클라이언트 비밀값, 승인 URL은 로그에 남기지 마세요.
Host 검사는 SDK의 localhost 검사를 대체합니다. 공개 요청의 Host가 명시적 포트까지 포함한 public_url의 호스트와 일치하지 않으면 421 응답을 반환합니다. 루프백 리스너는 상태 확인 요청을 위해 루프백 Host 값도 허용합니다. Host를 보존하는 리버스 프록시는 루프백 백엔드와 함께 사용할 수 있습니다. 와일드카드 리스너에는 로컬 요청을 위한 예외가 없습니다. 서명된 승인함 알림을 설정하면 정확히 POST /approvals/notify인 경로만 사설 서비스
전송을 위해 문법상 유효한 다른 Host도 허용합니다. 브라우저 자격 증명을 쓰지 않고
상수 시간 HMAC 비교, 서명된 시간·재전송 검사, 64 KiB 본문 제한, 전체 요청 속도 제한으로
인증·제한합니다. 식별자 알림만 제한하여 보관하며 승인 요청을 만들거나 실행하지 않습니다.
브라우저와 MCP 경로는 기존 Host 정책을 유지합니다. CORS와 MCP 애너테이션은 인가 경계가 아닙니다.
내장 OAuth는 다음 위협에 대응합니다.
- 인가 코드 가로채기: PKCE S256이 필수이며, implicit 및 password grant는 지원하지 않습니다.
- 리다이렉트 탈취: 인가와 코드 교환 시 리다이렉트 URI가 등록된 URI와 정확히 일치해야 합니다.
- 클라이언트 등록(DCR) 악용: 본문 크기, 메타데이터, 클라이언트 수와 등록 요청 빈도를 제한하며, grant와 인증 방식도 제한합니다. HTTPS 리다이렉트, 루프백 HTTP, 지원하는 네이티브 URI 스킴을 허용합니다. 수용 한도에 도달하면 생성 후 10분이 지난 미사용 등록을 오래된 순서로 제거하되, 토큰이나 진행 중인 인가가 있는 클라이언트는 제외합니다. 등록만으로는 도구 접근 권한을 주지 않습니다.
- 등록 정책:
allowed_redirect_hosts로 리다이렉트 목적지를 제한합니다. 목록이 비어 있지 않으면unknown_redirect_hosts: deny는 목록에 없는 호스트를 거부합니다.approve는 설정된 관리자가/admin/clients에서 검토할 때까지 클라이언트를 대기 상태로 둡니다. 관리자도 허용된 사용자여야 합니다.notify_url은 선택 사항이며, 대기 중인 등록의 JSON 알림을 받지만 전달을 보장하지는 않습니다. 호스트 목록이 비어 있으면 다른 유효성 조건을 만족하는 모든 리다이렉트 호스트를 허용하며, 목록에 없는 호스트에 대한 정책은 무시합니다. 등록을 승인해도 사용자 접근 권한을 주거나 동의를 생략하지는 않습니다. - DCR을 이용한 피싱: 동의 화면에 요청한 클라이언트, 리다이렉트 목적지, 스코프를 표시합니다. 클라이언트 이름은 신뢰할 수 없으며, 동의했다고 해서 클라이언트 소유권이 입증되지는 않습니다. 사람이 목적지와 요청 권한을 확인해야 합니다. 동의 전 인가 오류는 로컬에 표시하며, 동의 화면 이후의 Deny는 리다이렉트할 수 있습니다.
- 코드 및 리프레시 토큰 재사용: 일회용 코드를 사용하고 리프레시 토큰을 교체합니다. 재사용을 탐지하면 그 토큰에서 파생된 토큰 계열을 폐기합니다.
- 로그인 CSRF: 업스트림 로그인 상태를 브라우저에 연결하고, 동의와 웹 승인에는 CSRF 보호를 적용합니다. OIDC는 ID 토큰도 검증합니다.
- 상태 저장소의 자격 증명 유출: 불투명 액세스 토큰/리프레시 토큰과 클라이언트 비밀값은 원본 대신 해시로 저장합니다. 비밀값을 비교할 때는 상수 시간 검사를 사용하지만, 상태 파일과 백업은 따로 보호하세요. 상태 저장에 오류가 발생하면 처리를 거부합니다.
OAuth 응답은 공유 상태 잠금을 해제한 뒤 보냅니다. OAuth GET 경로는 본문을 거부하며, POST 본문 읽기의 제한 시간은 10초입니다. 대기 중인 인가는 클라이언트당 20개 또는 전체 1000개에 도달하면 가장 오래된 항목을 제거합니다. 웹 승인 및 관리자 로그인은 별도로 최대 256개까지 수용하며, 한 번에 20개와 이후 3초당 1개의 새 로그인을 허용하고, 트랜잭션 유효 기간은 10분이며 만료된 로그인 항목만 제거합니다. 요청 폭주 시 진행 중인 로그인은 만료 전까지 유지되지만 공유 제한기가 회복될 때까지 새 로그인이 지연될 수 있으므로(Retry-After가 포함된 HTTP 429), 리버스 프록시에서도 요청 빈도를 제한하세요. HTTP 접근 로그는 /approve/<id>를 /approve/*로 마스킹하고 쿼리 문자열을 생략합니다.
패스키 로그인(업스트림 passkey)에는 외부 인증 provider가 필요하지 않습니다. 등록에 필요한 일회용 초대는 무작위 256비트 토큰이며, 그 SHA-256 해시를 상태 파일 옆의 0600 파일에 저장합니다. TTL 동안 유효하고 기본값은 24h, 최대 7일입니다. 설정된 subject 하나에 연결되며 사용하면 삭제합니다. 처음 시작할 때 패스키가 없는 사용자의 초대를 로그에 기록하므로, 서비스 로그를 읽을 수 있는 사람은 그 사용자가 등록하기 전까지 그 사용자로 등록할 수 있습니다. 로그 접근을 제한하거나, 대신 opsgate passkey invite로 초대를 발급하세요.
패스키 자격 증명에는 사용자 검증과 resident key가 필요합니다. relying party ID는 public_url 호스트이며, 허용하는 origin은 public_url 하나입니다. 로그인 challenge는 각각 일회용이고 브라우저의 대기 중인 인가 쿠키에 연결됩니다. 서명 카운터가 증가하지 않으면 복제된 인증 장치로 간주해 거부합니다. 패스키를 잃어버리면 새 초대를 발급해야 하며, users에서 사용자를 제거하면 즉시 로그인을 차단합니다. 스크립트를 실행하는 페이지는 패스키 페이지뿐입니다. script-src 'self' 정책에 따라 같은 origin의 /passkey.js를 사용하며 인라인 스크립트는 없습니다.
builtin 로그인은 설정된 패스키 사용자(passkey:<name>), GitHub 로그인, 검증된 OIDC 이메일 ID, 또는 설정된 발급자의 oidc:<sub> ID만 허용합니다. 이 subject ID는 대소문자를 구분해 정확히 일치해야 합니다. Google 이메일 ID에는 Gmail/Googlemail 도메인이나 이메일 도메인과 일치하는 hd 클레임도 필요합니다. 다른 Google 주소는 변경되지 않는 subject를 사용해야 합니다. GitHub 로그인 이름이 바뀌면 로그인 허용 목록과 일치하는 사람이 달라질 수 있으므로, OIDC의 검증된 이메일을 우선 사용하거나 GitHub 허용 목록을 최신으로 유지하세요. external 모드는 discovery로 찾은 JWKS로 JWT 서명을 검증하고 발급자, audience, 만료 시간, 허용된 서명 알고리즘을 검사합니다. 발급자, discovery, JWKS URL에는 HTTPS가 필요하며 루프백 HTTP는 예외입니다. 외부 사용자 항목을 설정하면 ID와 스코프를 제한할 수 있습니다. static 모드는 SHA-256 토큰 다이제스트만 저장하며 대화형 OAuth 절차는 제공하지 않습니다.
Kubernetes 쓰기에는 별도의 작업 허용 목록이, 노트 쓰기에는 allow_write가 필요합니다. 이 쓰기 도구에는 ops:write, OS/RBAC 권한, 사람의 승인이 필요합니다. HTTP에는 ops:read도 필요합니다.
계획(Plan) 단계에서 실행 전에 대상을 검증하고 요약을 만듭니다. 클라이언트 내 확인(elicitation)은 MCP 입력 요청으로 클라이언트 안에서 승인 여부를 받는 방식입니다. builtin 인증과 approval.web: true를 사용하는 HTTP에서는 클라이언트 내 확인 지원 여부와 관계없이 기본적으로 웹 승인 링크를 제공합니다. 승인자는 같은 사용자로 업스트림에 로그인합니다. 승인은 유효 기간이 있고 한 번만 사용할 수 있으며, 정규화한 마스킹 전 인자(approval_id 제외)의 SHA-256과 정확한 계획에 연결됩니다. 마스킹으로 요약이 바뀌면 대상을 명확히 보여 줄 수 없으므로 쓰기를 거부합니다. Kubernetes 요약에는 UID를 포함하며, 실행(Apply)은 같은 호출에서 만든 계획을 받습니다. rollout은 JSON patch UID 검사를 사용하고, scale은 resourceVersion을 유지하며, 파드 삭제는 UID 사전 조건을 유지합니다. 인자를 바꿔 재시도하면 승인을 재사용할 수 없습니다. 확인 없이는 쓰기를 거부합니다.
승인 시간 창은 기본적으로 꺼져 있습니다. 활성화하려면 approval.window를 1m–12h로 설정하고 approval.window_tools에 도구 이름을 명시하는 path.Match glob을 넣으세요. 허용 목록이 비어 있으면 어떤 도구도 허용하지 않습니다. 사람은 웹 승인이나 클라이언트 내 확인에서 이 기능을 허용한 호출을 승인할 때 시간 창 사용을 선택할 수 있습니다. 승인 권한은 정확한 사용자/도구/대상 조합 하나에 적용되며, 클라이언트에는 한정되지 않습니다. 따라서 만료 전까지는 다른 클라이언트에서 같은 대상에 다른 인자로 보내는 유효한 후속 호출도 허용하지만, 대상이 바뀌면 새 승인이 필요합니다. 도구 허용 목록은 좁게, 시간 창은 짧게 설정하세요.
승인 권한이 있어도 스코프 검사, provider 정책, 계획, 인자 제한, 요약 마스킹 검사는 그대로 적용합니다. 권한은 메모리에만 보관하며, 활성 권한 수는 최대 100개입니다. 사용해도 유효 기간이 늘어나지 않으며 재시작하면 지웁니다. 권한을 만들 때 승인 방식, 기간, 만료 시간을 담은 별도의 window_granted 감사 이벤트를 기록합니다. 권한을 사용할 때마다 쓰기 래퍼가 approval: window를 감사 로그에 남깁니다. require_web을 설정하면 이 권한도 브라우저에서 받아야 하며 stdio 쓰기는 거부합니다. 침해된 클라이언트는 개별 클라이언트 내 확인 요청을 수락할 수 있는 것처럼, 클라이언트 내 확인에서 시간 창 사용도 선택할 수 있습니다.
쓰기 요청의 원시 JSON 크기는 기본적으로 16 KiB로 제한합니다. 노트 create/append/replace는 528 KiB(내용/치환 입력당 256 KiB)를 허용합니다. JSON 이스케이프도 전송 크기 제한에 포함됩니다. 승인 요약은 max(64 KiB, argument limit + 16 KiB)까지 허용하며, 표시용으로 마스킹한 인자는 도구의 인자 크기 제한을 넘지 않아야 합니다. 4 MiB를 초과하는 provider 출력은 통째로 생략합니다. 그 밖의 출력은 먼저 마스킹한 뒤 설정된 응답 상한(기본값 64 KiB)에 맞춰 자릅니다. 승인 및 동의 페이지는 이스케이프 처리하는 HTML 템플릿과 인라인 CSS를 공유합니다. 스크립트나 외부 자산은 사용하지 않으며, CSRF, 교차 origin, CSP, 캐시 보호를 유지합니다. 승인 링크와 CSRF 토큰은 승인 권한 감사 이벤트에 포함하지 않습니다.
approval.web이 활성화되면 approval.require_web의 기본값은 true입니다. builtin 인증을 쓰는 모드가 켠 경우도 포함합니다. approval.require_web: false를 명시하면 클라이언트 내 확인을 허용하며, 침해된 클라이언트가 자기 쓰기를 스스로 승인할 수 있습니다. 서버는 클라이언트가 제어하는 프롬프트를 실제 사람이 클릭했는지 확인할 수 없습니다. external/static 인증이나 approval.web: false에서는 웹 채널이 없어 require_web의 기본값이 false입니다. HTTP 시작 시 클라이언트 내 확인이 허용되어 있으면 경고를 남깁니다. 파일에서 require_web을 생략하면 모드 파일이라도 -transport stdio에서 클라이언트 내 확인을 허용합니다. 사용자가 로컬에서 시작한 프로세스이고 웹 채널이 없기 때문입니다. 명시적 true는 계속 stdio 쓰기를 거부합니다. config show는 HTTP 기본값을 명시하므로 stdio 쓰기를 하려면 출력의 require_web: true를 지우거나 false로 바꾸세요. 프롬프트 인젝션은 여전히 모델이 쓰기를 요청하게 할 수 있으므로, 사람은 승인 전에 요약과 대상을 읽어야 합니다. 승인했다고 해서 작업이 안전해지거나 대상 상태가 그대로라고 보장되지는 않습니다. OS 권한, RBAC, 좁은 허용 목록은 여전히 필수입니다. 감사 로그에는 계획, 승인 방식, 대기 결과, 웹 승인 결정(승인 ID 접두사만 포함), 여러 차례 왕복하는 승인 과정에서 거부한 검증을 기록합니다. 다만 감사 로그를 전달해야만 실행할 수 있는 것은 아닙니다.
알려진 제한 사항
- 익명 인가 요청이 대기 중인 연결 인가를 밀어내면 해당 클라이언트는 로그인을 다시 시작해야 할 수 있습니다.
- 여러 줄로 된 따옴표 안의 비밀값 할당은 첫 번째 줄만 마스킹합니다.
- 의존성 검사기는 고정된
x/crypto모듈에 GO-2026-5932를 보고할 수 있지만, opsgate는 영향을 받는 OpenPGP 패키지를 가져오거나 호출하지 않습니다. - 작업 로그와 diff는 전체 원본이 20 MiB를 넘으면 읽기에 실패합니다.
- 기존 승인 시간 창이 없으면 stdio는 약 8 KiB를 넘는 미리보기 검토가 필요한 노트 쓰기를 거부합니다.
- DATA 중 연결이 끊어지면 이메일 재시도로 같은 메시지가 중복 전달될 수 있습니다.
note provider
전체 검토가 필요한 경우 인자(approval_id 제외)가 마스킹으로 바뀌면 승인이나 승인 시간 창 재사용 전에 쓰기를 거부하므로, 변경을 나누거나 마스킹된 값을 제거하세요.
볼트 접근 범위는 os.Root로 제한합니다. 점으로 시작하는 경로와 동기화 충돌 복사본을 제외하며, 설정된 제외 규칙도 적용합니다. 볼트 내부의 안전한 심볼릭 링크는 지원하지만, 노트 텍스트와 파일명은 신뢰할 수 없습니다. 노트 쓰기 계획에는 대상, 마스킹된 현재/결과 텍스트의 해시, 약 8 KiB로 제한한 내용 미리보기 또는 diff를 표시하고 생략한 줄 수를 명시합니다. 기존의 유효한 승인 시간 창이 없으면 잘린 미리보기는 마스킹된 전체 인자를 보여 주는 웹 승인이 필요하며, 웹 승인을 사용할 수 없으면 변경을 더 작은 쓰기로 나누어야 합니다.
실행(Apply) 시에는 승인한 파일이 같은 파일인지 확인하고 해시, 크기, 수정 시간을 다시 검사합니다. 파일을 갱신할 때는 디스크에 동기화한 임시 파일을 rename으로 대상 경로에 반영합니다. 이는 외부 편집기와 트랜잭션을 보장하는 방식이 아니라, 실행 전에 상태를 다시 확인하는 낙관적 검사입니다. 검사와 rename 사이에 외부에서 편집하면 그 내용을 덮어쓸 수 있으므로, 동기화 도구의 버전 이력과 백업을 사용하세요. 새 파일을 만들 때는 동시에 같은 파일을 만드는 다른 작업의 결과를 덮어쓰지 않습니다. 휴지통으로 옮기면 노트를 영구 삭제하는 대신 로컬에 복사본을 보관합니다. 볼트와 백업은 파일시스템 권한으로 보호하세요.
호스트 provider
선택 기능인 호스트 provider는 기본값이 꺼짐이며 mode: kubernetes에서는 거부됩니다. 허용 목록에
있는, 검증한 유닛·컨테이너 이름만 받고, systemctl/journalctl은 셸 없이 고정된 인자로 제한
시간과 출력 상한을 두고 실행합니다. 재시작하려면 볼 수 있는 목록과 재시작 목록에 모두 있어야
하고 사람의 승인이 필요합니다. 유닛 재시작은 systemd D-Bus API와, 적어 둔 유닛의 restart만
허락하는 polkit 규칙을 거치므로 sudo가 필요 없고 NoNewPrivileges를 유지합니다. Docker는
목록, 상세, 로그, 재시작만 허락하는 소켓 프록시를 거쳐야 합니다. Docker 소켓 자체는 root와
같습니다. 컨테이너 재시작은 승인한 실행 계획의 컨테이너 ID에 묶입니다.
호스트 provider를 참고하세요.
지원 버전
프로젝트가 0.x인 동안은 최신 개발 버전을 중심으로 보안 수정과 지원을 제공하지만, 이를 보장하지는 않습니다. 이전 0.x 릴리스의 유지보수 기간도 보장하지 않습니다.
취약점 신고
GitHub Security Advisories로 비공개 신고하세요. 저장소의 Security 페이지에서 Report a vulnerability를 선택하고, 영향을 받는 리비전, 비밀값을 제거한 설정, 영향, 재현 단계를 포함하세요. 취약점은 공개 이슈로 등록하지 말고, 자격 증명도 공개하지 마세요. 유지보수자는 조사와 공개 절차를 비공개로 조율하지만, 응답 시간은 보장하지 않습니다.
선택적 분석기의 모델 backend
분석기는 API 모델 또는 설정된 Claude Code 또는 Codex CLI 실행 파일을 사용할 수 있습니다.
CLI 방식은 운영자가 관리하는 실행 파일을 고정 인자로 실행하며 셸을 사용하지
않습니다. 알림과 근거는 명령 인자가 아닌 표준 입력으로 전달합니다. CLI 옵션으로
기본 도구, 직접 MCP 연결, 사용자·프로젝트 설정, 훅과 세션 저장을 비활성화하지만
조직 관리 설정은 적용될 수 있습니다. MCP 조회 요청은 공통 엔진의 읽기 전용
정책으로 돌아옵니다. 실행 시간과 출력 크기를 제한하고 Linux/macOS에서는
취소 시 프로세스 그룹을 종료합니다. 이 제한은 악의적인 실행 파일을 OS 수준에서
격리하지 않으므로 CLI 설치와 인증 디렉터리를 보호해야 합니다. CLI 인증과
사용량 제한은 MCP 조회 전용 토큰과 별개이며 MCP 토큰은 CLI에 전달하지 않습니다.
-check는 실행 파일 존재만 확인하고 로그인 만료나 공급자 접근 권한은 검사하지
않습니다. 기본 컨테이너 이미지에는 Claude Code와 구독 로그인이 포함되지 않습니다.
Codex 방식은 호출별 로컬 모델 카탈로그로 셸·패치 도구를 제거하고 설정·기능 덮어쓰기와 JSONL 이벤트 검사를 함께 적용합니다. 직접 도구 이벤트가 나오면 중단합니다. CLI 0.166.0과 로컬 가짜 Responses 서버로 실제 요청의 도구 목록이 비어 있음을 검증했으며 CLI 업그레이드 시 이 계약을 재검사해야 합니다. 읽기 전용 샌드박스만으로 원격 MCP 쓰기를 제한할 수 있는 것은 아닙니다. MCP 토큰과 직접 서버 연결은 Codex에 제공하지 않고 공통 엔진이 조회 정책을 강제합니다. 인증 마운트는 보호해야 하며 토큰 갱신으로 디렉터리에 쓰기가 발생할 수 있습니다.