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

"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-write | active 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 policy | permission profile | 위험 수준 |
|---|---|---|---|---|
| 코드 리뷰/아키텍처 정리 | read-only | never | 설정 불필요 | 낮음 |
| 일상 개발/코드 수정 | workspace-write | on-request | .env deny 설정 | 중간-낮음 |
| 테스트 실행/의존성 설치 | workspace-write | on-request | .env deny, 스크립트 감사 | 중간 |
| CI 읽기 전용 검사 | read-only | never | 설정 불필요 | 낮음 |
| CI에서 파일 쓰기 필요 | workspace-write | never | deny 설정, isolated runner 사용 | 중간-높음 |
| full access 필요 | danger-full-access | never | 통제 환경에서만 | 높음 |
.env와 secret 파일 보호 설정 단계입니다.
- 사용하는 permission profile 설정 파일 경로를 확인합니다(Codex Permissions 문서 참고).
- filesystem 권한 설정에
"**/*.env" = "deny"를 추가합니다. - 더 구체적인 규칙이 넓은 규칙을 덮어쓰고 deny가 우선하는지 확인합니다.
- 테스트합니다.
workspace-write모드에서.env읽기를 시도하면 deny되어야 합니다. - 필요하면
"**/.env.local" = "deny","**/secrets/**" = "deny"등을 추가합니다.
구두 제약에 기대지 마세요. AGENTS.md는 안내이지 강제 접근 제어가 아닙니다. Codex가 지침을 따를 수도 있지만 다른 이유로 읽기가 발생할 수도 있습니다. 강제력은 permission profile의 deny에만 있습니다.
의존성 설치 위험: npm postinstall, pip hooks, Docker socket
의존성 설치는 단순한 파일 다운로드가 아닙니다. npm/pnpm의 postinstall, prepare, pip install의 hooks는 설치 중 자동 실행됩니다. 이 스크립트들은 환경 변수를 읽거나 네트워크 요청을 보내거나 시스템 파일을 수정할 수 있습니다.
위험 체크리스트:
- 알 수 없는 postinstall이 환경 변수를 읽을 수 있습니다.
.envdeny를 설정해도 postinstall은 spawned commands 환경에서 실행되므로 environment variables에 접근할 수 있습니다. - 네트워크 요청을 보낼 수 있습니다. 추가 바이너리 다운로드, 통계 전송, 비공개 저장소 연결 등이 가능합니다.
- 시스템 파일을 수정할 수 있습니다. 전역 설정을 쓰거나 PATH를 바꿀 수 있습니다.
감사 권장 사항:
- 먼저 스크립트와 출처를 확인합니다.
package.json의scripts필드와 pip 패키지의setup.py를 봅니다. - 신뢰할 수 있는 출처를 사용합니다. 의존성 버전을 고정하고, 알 수 없는 버전으로 자동 업그레이드하지 않게 합니다.
- 통제된 환경에서 승인합니다. 로컬 개발에서는
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 수명 주기:
- container 생성
- repo checkout
- setup script 실행
- 네트워크 설정 적용
- agent가 명령 루프 실행
- 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에서 실행하지 않습니다.
올바른 방법:
- 단일 invocation inline: 단일
codex execinvocation에만CODEX_API_KEY를 설정합니다.
- name: Run Codex
run: CODEX_API_KEY=${{ secrets.CODEX_API_KEY }} codex exec "review PR #${{ github.event.number }}"
- 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-strategy | drop-sudo | sudo 권한 제거 |
sandbox | - | read-only/workspace-write/danger-full-access 선택 |
allow-users | write 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를 무효화합니다.
다음 단계:
- 로그 감사: key 사용 기록을 확인하고 비정상 호출이 있는지 봅니다.
- token 폐기: 기존 key가 완전히 무효화되었고 유효한 session이 남지 않았는지 확인합니다.
- 출처 조사: 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에 출력하는 것을 막지는 못합니다. 보안은 계층으로 만듭니다.
빠른 자가 점검:
-
.envdeny 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 프로젝트 규칙: 프로젝트 규칙 작성법을 배우되, 이것이 권한 시스템이 아니라 안내라는 점을 기억합니다.
관련 글:
- AI coding 도구 전체 보기 2026: AI coding 도구 생태계를 전체적으로 이해합니다.
- GitHub Actions CI 기초: CI workflow의 기본 개념을 복습합니다.
- GitHub Actions 배포 전략: 배포에서 secrets 사용 경계를 이해합니다.
- 프런트엔드 API key 유출 위험: key를 프런트엔드나 저장소에 넣으면 안 되는 배경을 확인합니다.
Codex 작업에 최소 보안 경계 설정하기
작업 위험도에 따라 sandbox, approval, permission, secrets, CI job 경계를 선택해 쓰기 권한, 네트워크, 의존성 스크립트, API key가 같은 무방비 환경에 놓이지 않게 합니다.
⏱️ Estimated time: 30 min
- 1
Step 1: 먼저 작업에 읽기, 쓰기, 네트워크가 필요한지 판단합니다
리뷰와 계획은 read-only에서 시작합니다. 코드 수정은 workspace-write + on-request를 사용하고, full access는 격리된 runner나 통제된 컨테이너에서만 씁니다. - 2
Step 2: 민감 파일을 읽기 범위 밖으로 옮기거나 명시적으로 deny합니다
.env, *.pem, credentials.json, secrets 디렉터리에 deny-read를 설정합니다. AGENTS.md의 구두 제약에만 기대지 마세요. - 3
Step 3: 의존성 설치를 승인하기 전에 스크립트를 확인합니다
package.json, postinstall, prepare, pip hooks, 다운로드 스크립트, 네트워크 대상을 확인한 뒤 install 또는 network 허용 여부를 결정합니다. - 4
Step 4: Cloud setup과 agent phase를 분리합니다
비공개 저장소 token과 의존성 인증은 Cloud secrets에 두고 setup scripts에서만 사용합니다. agent phase에는 필요한 비민감 env var만 남깁니다. - 5
Step 5: CI의 Codex job과 쓰기 권한 job을 분리합니다
API key를 job-level env에 두지 마세요. Codex job은 가능한 한 읽기 전용으로 patch artifact를 만들고, 댓글, PR, merge는 이후 통제된 job에서 처리합니다. - 6
Step 6: 출력을 검수하고 key rotation을 준비합니다
diff, 로그, artifact, 테스트 결과를 확인합니다. 유출이 의심되면 원인 조사보다 먼저 key를 rotation합니다.
FAQ
AGENTS.md에 '.env를 읽지 말라'고 쓰면 충분한가요?
workspace-write에서 Codex가 .env, ~/.ssh, /tmp를 읽을 수 없나요?
언제 Codex에 danger-full-access를 줄 수 있나요?
Cloud의 secret은 Codex agent가 읽을 수 있나요?
CI에서 codex exec를 실행할 때 API key는 어떻게 보호하나요?
Codex Security가 SAST나 수동 보안 리뷰를 대체할 수 있나요?
4분 읽기 · 게시일: 2026년 7월 26일 · 수정일: 2026년 7월 27일
OpenAI Codex 실전 가이드
검색으로 들어왔다면 같은 시리즈의 이전 글이나 다음 글로 이동하는 것이 가장 빠릅니다.
이전
codex exec로 Issue, Changelog, 문서 점검 자동화하기
codex exec의 stdin, JSONL, Schema 출력을 활용해 Changelog, Issue 분류, 문서 점검을 구성하고 CI 쓰기 권한을 분리하는 방법입니다.
10편 중 7편
다음
Codex 실패 사례 검증: AI가 코드를 망가뜨리는 이유와 검수 절차
Codex 변경을 검수하는 실전 가이드입니다. 지나치게 큰 diff, 약해진 테스트, CI 우회, review 부재, 모호한 scope를 찾고 scope, plan, patch, verify, review, rollback으로 merge 전에 확인합니다.
10편 중 9편



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