테마 전환

Codex 보안 경계 실전: 권한, 샌드박스, secrets 유출 방지

Easton editorial illustration: terminal-to-editor relay

"OpenAI Codex 보안 문서는 sandbox mode, approval policy, Cloud setup/agent phase, network proxy, secrets 수명 주기를 설명하며, 이 글의 보안 경계 판단에서 핵심 근거입니다."

프로젝트 루트에 .env 파일이 있고, 그 안에는 데이터베이스 비밀번호와 서드파티 API key가 들어 있습니다. Codex를 열어 테스트 코드 리팩터링을 맡기려 합니다. 드롭다운에는 read-only, workspace-write, danger-full-access 세 가지가 있습니다. 무엇을 선택해야 할까요?

workspace-write를 선택한 뒤 Codex가 npm install 승인 요청을 띄웁니다. 당신은 승인합니다. 그런데 package.json에 숨어 있던 postinstall 스크립트가 이 단계에서 환경 변수를 읽거나, 모르는 서비스로 요청을 보내지 않는다고 확신할 수 있을까요?

Codex를 GitHub Actions에 넣어 PR review를 자동화합니다. workflow 파일에는 OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}라고 적혀 있습니다. secrets니까 안전하다고 생각할 수 있습니다. 하지만 같은 job에서 실행되는 테스트 스크립트, third-party action, 의존성 설치 hooks도 이 key를 읽을 수 있습니다.

세 가지 경계가 이 질문에 바로 답합니다. instruction은 permission이 아니고, approval은 isolation이 아니며, sandbox는 audit이 아닙니다. 이제 로컬, Cloud, CI 세 환경에서 쓸 수 있는 최소 권한 체크리스트를 정리해 보겠습니다.

권한은 말로 막는 것이 아닙니다: sandbox, approval, permission profile 세 계층 이해하기

많은 사람이 AGENTS.md에 “.env 파일을 읽지 말라”는 한 줄을 쓰면 Codex가 민감 정보에 접근하지 못한다고 생각합니다. 하지만 이것은 권한 제어가 아니라 프로젝트 규칙 안내입니다. 실제 보안 경계는 세 계층에서 나옵니다. spawned commands의 범위를 제한하는 sandbox, 언제 멈춰서 물어볼지를 정하는 approval policy, 강제 접근 제어인 permission profile입니다.

Codex 보안은 한 계층만으로 충분하지 않습니다. sandbox는 git, 패키지 매니저, test runner 같은 spawned commands가 무엇에 접근할 수 있는지를 결정합니다. approval policy는 Codex가 중요한 작업 전에 사용자의 승인을 받아야 하는지를 결정합니다. permission profile은 "**/*.env" = "deny" 같은 규칙을 실제로 쓸 수 있는 설정 계층입니다. 이 세 계층이 겹쳐야 실제 권한이 됩니다.

sandbox 모드 비교: read-only, workspace-write, danger-full-access

sandbox 모드정의적합한 상황위험
read-only파일 읽기만 허용하고 쓰기나 명령 실행은 허용하지 않음코드 리뷰, 아키텍처 정리, 문서 생성, CI 읽기 전용 검사runner의 모든 secrets를 보호하지는 못함. 프로세스는 여전히 runner에서 실행됨
workspace-writeactive workspace에 쓰기를 허용하고 네트워크는 기본적으로 닫음일상적인 로컬 개발, 코드 수정, 테스트 실행workspace 아래의 모든 파일을 기본적으로 읽을 수 있으며 .env도 포함될 수 있음. deny glob 필요
danger-full-access파일 시스템과 네트워크 경계를 제거isolated CI runner/container, 완전히 통제된 테스트 환경~/.ssh, /tmp, 환경 변수, 로컬 서비스에 접근 가능. 일상 기본값으로 쓰지 않음

sandbox가 제한하는 대상은 Codex의 내장 파일 작업뿐이 아닙니다. spawned commands도 제한합니다. git, 패키지 매니저, test runner 모두 같은 sandbox 경계를 상속합니다. 플랫폼 전제도 신뢰성에 영향을 줍니다. Linux/WSL2는 bubblewrap 또는 user namespace에 의존하고, macOS는 시스템 sandbox에 의존하며, Windows는 sandbox 사용 가능 조건의 영향을 받습니다.

approval policy는 언제 멈춰서 물어볼지를 정합니다.

approval policy정의흔한 조합실제 권한
on-request작업 전에 일시 정지하고 승인을 요청로컬 자동화의 workspace-write + on-request낮은 위험. 파일 쓰기, 명령 실행, 네트워크 요청을 사람이 확인 가능
never대화형 승인 없이 바로 실행CI 읽기 전용 검사의 read-only + never; 통제 환경의 danger-full-access + never높은 위험. permission profile 없는 workspace-write + never는 위험함

낮은 위험 조합은 read-only + never(CI 읽기 전용)와 workspace-write + on-request(로컬 개발)입니다. 높은 위험 조합은 danger-full-access + never이며, 통제된 환경에서만 사용해야 합니다.

permission profile 설정: filesystem deny, network rules

permission profile은 강제 접근 제어이지 구두 제약이 아닙니다. filesystem 권한은 read/write/deny를 지원합니다. 더 구체적인 규칙이 더 넓은 규칙을 덮어쓰고, deny가 우선합니다.

.env deny glob 설정 예시는 다음과 같습니다.

{
  "filesystem": {
    "rules": {
      "**/*.env": "deny",
      "**/.env.local": "deny",
      "**/secrets/**": "deny",
      "workspace/**": "write"
    }
  }
}

이 설정을 적용하면 workspace-write에서도 .env 파일은 읽을 수 없습니다. workspace가 기본적으로 쓰기 가능하더라도 마찬가지입니다. deny가 우선하고, 구체적인 규칙이 넓은 규칙을 덮어씁니다.

network profile은 enabled = true와 domain allow/deny를 설정할 수 있으며 여기서도 deny가 우선합니다. local/private network에는 기본 보호가 있고, localhost나 Docker socket 허용은 명시적 예외입니다. Docker socket은 로컬 escape hatch입니다. 로컬 서비스, 컨테이너, 네트워크에 접근할 수 있으므로 신중하게 열어야 합니다.

network proxy는 이미 네트워크 접근이 켜진 명령의 네트워크 사용을 제한하는 장치이며, 그 자체로 네트워크 권한을 부여하지 않습니다. 전역 * allow는 넓은 네트워크 접근이므로 조심해야 합니다.

로컬 환경 최소 권한 체크리스트: 읽기 전용 리뷰부터 full access까지

로컬 개발에서 권한이 클수록 편한 것은 아닙니다. approval은 일부 작업을 막을 수 있지만, 실제 격리는 sandbox와 permission profile이 담당합니다. 가장 좁은 권한에서 시작해 작업에 맞게 단계적으로 넓히세요.

권한 선택 결정표: read-only를 쓸 때와 workspace-write를 쓸 때

상황sandbox 모드approval policypermission profile위험 수준
코드 리뷰/아키텍처 정리read-onlynever설정 불필요낮음
일상 개발/코드 수정workspace-writeon-request.env deny 설정중간-낮음
테스트 실행/의존성 설치workspace-writeon-request.env deny, 스크립트 감사중간
CI 읽기 전용 검사read-onlynever설정 불필요낮음
CI에서 파일 쓰기 필요workspace-writeneverdeny 설정, isolated runner 사용중간-높음
full access 필요danger-full-accessnever통제 환경에서만높음

.env와 secret 파일 보호 설정 단계입니다.

  1. 사용하는 permission profile 설정 파일 경로를 확인합니다(Codex Permissions 문서 참고).
  2. filesystem 권한 설정에 "**/*.env" = "deny"를 추가합니다.
  3. 더 구체적인 규칙이 넓은 규칙을 덮어쓰고 deny가 우선하는지 확인합니다.
  4. 테스트합니다. workspace-write 모드에서 .env 읽기를 시도하면 deny되어야 합니다.
  5. 필요하면 "**/.env.local" = "deny", "**/secrets/**" = "deny" 등을 추가합니다.

구두 제약에 기대지 마세요. AGENTS.md는 안내이지 강제 접근 제어가 아닙니다. Codex가 지침을 따를 수도 있지만 다른 이유로 읽기가 발생할 수도 있습니다. 강제력은 permission profile의 deny에만 있습니다.

의존성 설치 위험: npm postinstall, pip hooks, Docker socket

의존성 설치는 단순한 파일 다운로드가 아닙니다. npm/pnpmpostinstall, prepare, pip install의 hooks는 설치 중 자동 실행됩니다. 이 스크립트들은 환경 변수를 읽거나 네트워크 요청을 보내거나 시스템 파일을 수정할 수 있습니다.

위험 체크리스트:

  • 알 수 없는 postinstall이 환경 변수를 읽을 수 있습니다. .env deny를 설정해도 postinstall은 spawned commands 환경에서 실행되므로 environment variables에 접근할 수 있습니다.
  • 네트워크 요청을 보낼 수 있습니다. 추가 바이너리 다운로드, 통계 전송, 비공개 저장소 연결 등이 가능합니다.
  • 시스템 파일을 수정할 수 있습니다. 전역 설정을 쓰거나 PATH를 바꿀 수 있습니다.

감사 권장 사항:

  1. 먼저 스크립트와 출처를 확인합니다. package.jsonscripts 필드와 pip 패키지의 setup.py를 봅니다.
  2. 신뢰할 수 있는 출처를 사용합니다. 의존성 버전을 고정하고, 알 수 없는 버전으로 자동 업그레이드하지 않게 합니다.
  3. 통제된 환경에서 승인합니다. 로컬 개발에서는 workspace-write + on-request를 사용하고, 승인 전에 Codex가 무엇을 설치하려는지 확인합니다.

Docker socket은 로컬 escape hatch입니다. Docker socket을 허용하면 로컬 서비스, 컨테이너, 네트워크에 접근할 수 있습니다. 명확히 필요할 때만 설정하고 기본으로 열어 두지 마세요.

Cloud 환경 경계: setup vs agent phase, secrets 수명 주기

Cloud task는 로컬이 아니라 OpenAI가 호스팅하는 격리 컨테이너에서 실행됩니다. sandbox는 spawned commands를 제한할 수 있지만, secret 보호의 핵심은 Cloud secrets의 수명 주기입니다. setup 단계에서 사용할 수 있고 agent phase 전에 제거됩니다. sandbox는 audit이 아니며, 실제 안전성은 계층 분리에서 나옵니다.

Cloud container 수명 주기:

  1. container 생성
  2. repo checkout
  3. setup script 실행
  4. 네트워크 설정 적용
  5. agent가 명령 루프 실행
  6. answer/diff 출력

setup vs agent phase 경계: secrets는 setup에서만 사용

단계네트워크 접근secrets 사용 가능environment variables의존성 설치
setup scripts가능가능전체 기간 존재설치 가능
agent phase기본적으로 오프라인제거됨전체 기간 존재기본적으로 오프라인

setup 단계에서는 네트워크를 사용할 수 있고, 의존성을 설치할 수 있으며, secrets도 사용할 수 있습니다. agent phase는 기본적으로 오프라인이고 secrets는 제거되며 environment variables만 남습니다.

setup scripts는 별도의 Bash session에서 실행되므로 export가 자동으로 agent phase에 전달되지 않습니다. setup에서 export MY_KEY=xxx를 해도 agent phase는 이 변수를 상속하지 않습니다. 단계 사이를 넘어가는 것은 Cloud secrets와 environment variables뿐입니다.

secrets vs environment variables: 핵심 차이

유형암호화사용 가능 단계용도수명 주기
environment variables추가 암호화 없음setup + agent 전체비민감 설정, 경로, 스위치container 수명 동안 계속 존재
secrets추가 암호화setup scripts에서만비공개 저장소 접근, 의존성 설치 인증agent phase 전에 제거

secrets는 setup scripts에서만 사용할 수 있으며 의존성 설치나 비공개 저장소 연결에 적합합니다. agent phase에는 프로덕션 secrets가 없어야 합니다. environment variables는 전체 기간 존재하므로 비민감 설정에 적합합니다.

의존성 설치 경계:

  • setup phase에서는 네트워크로 의존성을 설치할 수 있습니다.
  • agent phase는 기본적으로 오프라인입니다.
  • setup scripts는 secrets에 접근할 수 있으므로 알 수 없는 스크립트가 유출시킬 수 있습니다.
  • 권장: 스크립트와 출처를 먼저 확인하고, 신뢰할 수 있는 출처를 사용하며, setup에서 알 수 없는 스크립트를 실행하지 않습니다.

container cache는 최대 12시간입니다. setup, maintenance, env, secrets 변경은 cache invalidation을 유발합니다.

CI 환경과 GitHub Action: codex exec, API key 금기, official Action 보안 전략

codex exec의 기본 sandbox는 read-only입니다. 하지만 많은 workflow가 OPENAI_API_KEY를 job-level environment variable로 둡니다. 같은 job의 테스트 스크립트, third-party actions, dependency lifecycle scripts가 이 key를 읽을 수 있습니다. sandbox는 audit이 아니며, 안전성은 최소 권한과 key 보호에서 나옵니다.

API key 금기: job-level env에 두지 않기

checkout하거나 저장소 코드를 실행하는 workflow에서 OPENAI_API_KEY 또는 CODEX_API_KEY를 job-level environment variable로 두지 마세요. 저장소 코드, 테스트, 의존성 lifecycle scripts, third-party actions는 같은 job에서 환경 변수에 접근할 수 있습니다.

금기 체크리스트:

  • OPENAI_API_KEY를 job-level env로 두지 않습니다.
  • checkout하거나 저장소 코드를 실행하는 workflow에 job-level key를 설정하지 않습니다.
  • auth.json / ChatGPT-managed auth는 public/open-source repo workflow에 적합하지 않습니다.
  • 신뢰할 수 없는 코드를 같은 process environment에서 실행하지 않습니다.

올바른 방법:

  1. 단일 invocation inline: 단일 codex exec invocation에만 CODEX_API_KEY를 설정합니다.
- name: Run Codex
  run: CODEX_API_KEY=${{ secrets.CODEX_API_KEY }} codex exec "review PR #${{ github.event.number }}"
  1. official Action proxy: openai/codex-action@v1의 proxy를 사용합니다.
- uses: openai/codex-action@v1
  with:
    prompt: "review PR #${{ github.event.number }}"
    sandbox: read-only
    safety-strategy: drop-sudo

CI에서 danger-full-access는 isolated CI runner/container에만 적합합니다. 기본값으로 쓰면 안 됩니다. runner의 모든 리소스에 접근할 수 있기 때문입니다.

GitHub Action 보안 체크리스트: 트리거 제한, key 보호, key rotation

official Action 파라미터:

파라미터기본값설명
safety-strategydrop-sudosudo 권한 제거
sandbox-read-only/workspace-write/danger-full-access 선택
allow-userswrite access 사용자특정 사용자만 트리거 가능
allow-bots-bot 트리거 허용 여부

read-only가 runner의 모든 secrets를 보호한다는 뜻은 아닙니다. Action은 여전히 runner에서 실행되고, 파일 시스템을 읽기 전용으로 제한할 뿐입니다. drop-sudo는 sudo 권한을 제거합니다. sandbox는 작업을 완료하는 데 필요한 가장 좁은 모드를 선택해야 합니다.

GitHub Action 보안 체크리스트:

  • 트리거 사용자 제한: allow-users는 특정 사용자만, allow-bots는 신중하게 활성화합니다.
  • PR/issue/prompt 입력 정리: prompt injection을 막고 신뢰할 수 없는 입력을 Codex에 그대로 넣지 않습니다.
  • API key 보호: job-level env에 두지 말고 단일 invocation inline 또는 proxy를 사용합니다.
  • Codex를 마지막 단계에서 실행: key 노출 시간을 줄입니다.
  • 유출이 의심되면 key rotation: 먼저 조사하지 말고 먼저 피해를 줄입니다.

PR/issue/prompt 입력은 신뢰할 수 없는 것으로 간주해야 합니다. PR comment나 issue body를 Codex prompt에 그대로 넣지 마세요.

secret 유출 대응: 의심되는 유출을 발견한 뒤 첫 번째 조치

유출이 의심되면 첫 번째 조치는 원인 조사가 아니라 key rotation입니다. 먼저 피해를 막고, 그다음 감사합니다. sandbox는 spawned commands를 제한할 수 있지만 Codex가 key를 로그, PR comment, answer에 출력하는 것까지 막지는 못합니다.

secret 유출 대응 단계: key rotation, 감사, 폐기

첫 번째 단계는 key rotation입니다. 출처를 찾기 전에 기존 key를 무효화합니다.

다음 단계:

  1. 로그 감사: key 사용 기록을 확인하고 비정상 호출이 있는지 봅니다.
  2. token 폐기: 기존 key가 완전히 무효화되었고 유효한 session이 남지 않았는지 확인합니다.
  3. 출처 조사: Codex log, GitHub Action 출력, 의존성 설치 스크립트, third-party actions를 확인합니다.

예방 조치:

  • API key를 프런트엔드 코드나 저장소에 넣지 않습니다.
  • API key를 job-level env로 두지 않습니다(CI).
  • permission profile deny로 .env를 보호합니다.
  • OWASP Secrets Management Cheat Sheet 권장처럼 key를 정기적으로 rotation합니다.

Codex Security의 경계: SAST를 대체하지 않고 patch를 자동 적용하지 않음

Codex Security는 LLM-driven security analysis toolkit이며 ephemeral isolated container에서 실행되고 구조화된 finding과 patch 제안을 출력합니다. 취약점 발견과 검증을 도울 수 있지만 SAST나 수동 보안 리뷰를 대체하지 않습니다.

한계 체크리스트:

  • SAST를 대체하지 않습니다.
  • manual security review를 대체하지 않습니다.
  • proposed patch는 사용자의 review가 필요하며 자동 적용되지 않습니다.
  • 목적은 발견, 검증, 제안을 보조하는 것이지 자동 수정이 아닙니다.

Codex Security를 만능 보안 스캐너로 다루지 마세요. AI-driven analysis가 일부 문제를 찾을 수는 있지만 실제 보안은 계층에서 나옵니다. 읽기 범위, 쓰기 범위, 네트워크, secrets, approval, review, 폐기입니다.

결론

Codex의 보안 경계는 세 계층에서 나옵니다. sandbox는 spawned commands의 범위를 제한하고, approval policy는 언제 멈춰서 물어볼지 결정하며, permission profile은 강제 접근 제어입니다. 세 계층이 합쳐져 실제 권한이 됩니다.

기억해야 할 세 가지 경계입니다.

  • instruction은 permission이 아닙니다. AGENTS.md는 안내이지 강제 접근 제어가 아닙니다. .env와 API key를 구두 제약으로 보호하지 마세요.
  • approval은 isolation이 아닙니다. approval policy는 일부 작업을 멈출 수 있지만 실제 격리는 sandbox와 permission profile에서 나옵니다.
  • sandbox는 audit이 아닙니다. sandbox는 spawned commands를 제한할 수 있지만 Codex가 key를 로그, PR comment, answer에 출력하는 것을 막지는 못합니다. 보안은 계층으로 만듭니다.

빠른 자가 점검:

  • .env deny glob을 설정했나요?
  • CI에서 job-level API key를 피하고 있나요?
  • GitHub Action 트리거 사용자를 제한했나요?
  • 의존성 설치 스크립트를 감사했나요?
  • key rotation 계획이 있나요?

보안 경계는 논리 버그까지 막아 주지 않습니다. Codex가 모든 권한 규칙을 지켜도 생성된 코드에 bug가 있을 수 있고, 테스트가 실패할 수 있으며, rollback이 필요할 수 있습니다. diff를 검수하고, 테스트를 실행하고, rollback 계획을 준비하는 것이 보안 경계 바깥의 두 번째 방어선입니다.

다음 단계:

  • 실패 회고와 검수 흐름: Codex가 실패했을 때의 처리, diff 검수, rollback 전략을 이해합니다.
  • codex exec 자동화와 CI: CI의 비대화형 모드, workflow 설계, 오류 처리를 더 깊게 봅니다.
  • AGENTS.md 프로젝트 규칙: 프로젝트 규칙 작성법을 배우되, 이것이 권한 시스템이 아니라 안내라는 점을 기억합니다.

관련 글:

Codex 작업에 최소 보안 경계 설정하기

작업 위험도에 따라 sandbox, approval, permission, secrets, CI job 경계를 선택해 쓰기 권한, 네트워크, 의존성 스크립트, API key가 같은 무방비 환경에 놓이지 않게 합니다.

⏱️ Estimated time: 30 min

  1. 1

    Step 1: 먼저 작업에 읽기, 쓰기, 네트워크가 필요한지 판단합니다

    리뷰와 계획은 read-only에서 시작합니다. 코드 수정은 workspace-write + on-request를 사용하고, full access는 격리된 runner나 통제된 컨테이너에서만 씁니다.
  2. 2

    Step 2: 민감 파일을 읽기 범위 밖으로 옮기거나 명시적으로 deny합니다

    .env, *.pem, credentials.json, secrets 디렉터리에 deny-read를 설정합니다. AGENTS.md의 구두 제약에만 기대지 마세요.
  3. 3

    Step 3: 의존성 설치를 승인하기 전에 스크립트를 확인합니다

    package.json, postinstall, prepare, pip hooks, 다운로드 스크립트, 네트워크 대상을 확인한 뒤 install 또는 network 허용 여부를 결정합니다.
  4. 4

    Step 4: Cloud setup과 agent phase를 분리합니다

    비공개 저장소 token과 의존성 인증은 Cloud secrets에 두고 setup scripts에서만 사용합니다. agent phase에는 필요한 비민감 env var만 남깁니다.
  5. 5

    Step 5: CI의 Codex job과 쓰기 권한 job을 분리합니다

    API key를 job-level env에 두지 마세요. Codex job은 가능한 한 읽기 전용으로 patch artifact를 만들고, 댓글, PR, merge는 이후 통제된 job에서 처리합니다.
  6. 6

    Step 6: 출력을 검수하고 key rotation을 준비합니다

    diff, 로그, artifact, 테스트 결과를 확인합니다. 유출이 의심되면 원인 조사보다 먼저 key를 rotation합니다.

FAQ

AGENTS.md에 '.env를 읽지 말라'고 쓰면 충분한가요?
충분하지 않습니다. AGENTS.md는 Codex 동작을 안내하는 custom instructions이지 filesystem이나 network permission enforcement가 아닙니다. 읽기를 강제로 막으려면 permission profile에서 deny를 설정하거나 민감 파일을 workspace 밖으로 옮겨야 합니다.
workspace-write에서 Codex가 .env, ~/.ssh, /tmp를 읽을 수 없나요?
기본적으로 읽을 수 없다고 가정하면 안 됩니다. workspace-write는 주로 active workspace에 대한 쓰기를 제한합니다. 민감 파일이 읽기 가능한 범위에 있고 deny가 없다면 격리된 것이 아닙니다. danger-full-access는 파일 시스템과 네트워크 경계를 더 제거합니다.
언제 Codex에 danger-full-access를 줄 수 있나요?
isolated CI runner, 컨테이너, 또는 명확히 통제된 일회성 환경에서만 고려해야 합니다. 그 환경에는 프로덕션 secrets, 개인 SSH key, 불필요한 내부망 접근, 브라우저 로그인 상태가 없어야 합니다.
Cloud의 secret은 Codex agent가 읽을 수 있나요?
OpenAI Codex Cloud 환경 문서에 따르면 secrets는 setup scripts에서만 사용할 수 있고 agent phase에 들어가기 전에 제거됩니다. 반면 environment variables는 setup과 agent phase 모두에 남습니다.
CI에서 codex exec를 실행할 때 API key는 어떻게 보호하나요?
OPENAI_API_KEY 또는 CODEX_API_KEY를 checkout하거나 저장소 코드를 실행하는 job-level env에 설정하지 마세요. official Codex GitHub Action의 proxy를 우선 사용하거나, 단일 codex exec invocation에만 CODEX_API_KEY를 주입합니다.
Codex Security가 SAST나 수동 보안 리뷰를 대체할 수 있나요?
대체할 수 없습니다. 발견, 검증, patch 제안은 도울 수 있지만 SAST, manual security review, threat modeling, 최종 사람 검수를 대신하지 않습니다.

4분 읽기 · 게시일: 2026년 7월 26일 · 수정일: 2026년 7월 27일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog