Express 코드 9줄이 들어 있는 파일 하나짜리 저장소에 새 Codex Security CLI를 실행해 봤다. 8분 30초가 지난 뒤 스캔은 $6.00 한도에서 멈췄고, 입력 토큰 700만 개를 사용한 끝에 1,605단어 분량의 위협 모델과 취약점 0건을 남겼다. CI에 이 도구를 붙이려는 사람이라면 여기서 핵심을 짚어야 한다. 비용은 코드 줄 수가 아니라 에이전트의 추론 루프를 따라 움직인다. 따라서 무엇보다 먼저 --max-cost부터 설정해야 한다.
그래도 이 도구를 알아둘 가치는 충분하다. GitHub App에 저장소를 넘기지 않고 직접 실행할 수 있는 첫 Codex Security 버전이기 때문이다.
Codex Security CLI가 하는 일과 하지 않는 일
Codex Security 자체가 처음 나온 서비스는 아니다. OpenAI는 2026년 3월 이를 호스팅형 리서치 프리뷰로 공개했다. GitHub 저장소를 연결하면 격리 환경에서 위협 모델을 만들고 커밋 기록을 스캔한 뒤, ChatGPT 워크스페이스에서 결과를 보고하는 방식이다. SecurityWeek 보도에 따르면 ChatGPT Pro, Enterprise, Business, Edu 고객이 이용할 수 있다.
2026년 7월 28일 공개된 것은 성격이 다르다. openai/codex-security는 Apache-2.0 라이선스의 CLI 및 TypeScript SDK다. npm에 게시된 버전은 17:09 UTC 기준 0.1.0이었고, 같은 날 23:48 UTC에 0.1.1이 뒤따랐다. 작성 시점 기준 별 1.8k개와 열린 이슈 28개가 보인다. 공개 첫날의 프로젝트다.
설치에는 Node.js 22 이상과 Python 3.10 이상이 필요하다. 스캔 엔진이 번들 Python 플러그인으로 제공되기 때문이다.
npm install @openai/codex-security
npx codex-security info
어떤 구성으로 설치됐는지 가장 빨리 확인하려면 info를 실행하면 된다.
sdkVersion: 0.1.1
bundledPluginVersion: 0.1.14
cliVersion: 0.1.1
codexVersion: 0.144.6
model: gpt-5.6-sol
reasoningEffort: xhigh
비용을 좌우하는 것은 마지막 두 줄이다. 이 설치에서는 기본값으로 GPT-5.6 Sol과 xhigh 추론 강도를 사용한다. --model로 모델은 바꿀 수 있지만, 플러그인의 중심은 깊게 반복하는 에이전트 루프이고 실제 비용도 여기서 발생한다.
명령 범위는 호스팅형 제품에서 예상하는 것보다 넓다. scan, validate, patch, scans(목록, 조회, 재실행, 매칭, 비교), bulk-scan, CSV·JSON·SARIF 형식의 export, install-hook, 그리고 도구를 MCP 서버로 등록하는 mcp 모드까지 제공한다. 다만 info에는 scanMcp: false가 표시된다. MCP 전송에서는 스캔을 취소할 수 없기 때문이다.
인증 방식은 두 가지, 실제로 막히는 지점은 따로 있다
npx codex-security login은 ChatGPT 계정으로 로그인하고, 헤드리스 머신에서는 --device-auth를 쓰면 된다. CI에서는 OPENAI_API_KEY를 사용한다. API 키와 로그인 세션이 모두 있으면 대화형 스캔은 어느 쪽을 쓸지 묻고, 비대화형 실행에서는 API 키가 우선한다.
공식 문서에서 특히 주의해서 읽어야 할 부분도 있다. 전체 저장소 스캔에는 추가로 Trusted Access for Cyber 권한이 필요할 수 있으며, 로그인이나 API 키 설정만으로는 이 권한이 부여되지 않는다. 로그인 절차가 아니라 접근 권한 요청까지 고려해야 한다.
호환 엔드포인트에서 OpenAI Codex Security CLI 실행하기
OPENAI_API_KEY에 서드파티 키를 넣으면 그쪽 엔드포인트로 연결될 것이라고 생각하기 쉽지만, 가장 먼저 실패하는 지점이 바로 이것이다.
codex-security: Authentication failed using OPENAI_API_KEY.
키만으로 대상이 바뀌지는 않는다. 내장된 Codex 런타임은 여전히 OpenAI 기본 URL을 향하며 OPENAI_BASE_URL도 무시한다. --codex로 TOML 값을 넘겨 프로바이더 설정을 직접 덮어써야 한다.
OPENAI_API_KEY=sk-... npx codex-security scan . --auth api-key --max-cost 5 \
--codex 'model_provider="relay"' \
--codex 'model_providers.relay.name="relay"' \
--codex 'model_providers.relay.base_url="https://your-endpoint/api/v1"' \
--codex 'model_providers.relay.env_key="OPENAI_API_KEY"' \
--codex 'model_providers.relay.wire_api="responses"'
여기에는 실행 한 번씩을 날릴 수 있는 함정이 두 가지 있다. 값을 따옴표로 감싸지 않으면 Invalid --codex TOML value 오류가 난다. 또 wire_api="chat"은 Codex 0.144.6에서 아예 거부된다. 오류 메시지는 discussion #7782를 가리키며 responses를 사용하라고 안내한다. 엔드포인트는 Chat Completions뿐 아니라 Responses API도 구현해야 한다.
모델 비용이 어디에 청구되는지도 같은 설정에서 알 수 있다. CLI는 어느 엔드포인트를 가리키든 항상 GPT-5.6 Sol의 OpenAI 정가를 기준으로 추정 비용을 계산한다. 즉, 실행 중 표시되는 금액은 실제 청구서가 아니라 토큰 수 기반 계산값이다. 정가의 절반으로 과금하는 엔드포인트로 같은 트래픽을 보낸다면 아래의 $6.03 실행은 실제로 약 $3가 들겠지만, CLI는 계속 $6.03을 출력한다.
스캔 한 번에 실제로 든 비용
아래 수치에는 전제가 하나 있다. 다섯 번의 실행은 모두 서드파티 OpenAI 호환 엔드포인트를 경유했다. 공식 경로를 시험할 ChatGPT Business 또는 Enterprise 로그인 계정이 없었기 때문이다. 따라서 이 결과는 권한이 부여된 계정에서 호스팅 서비스를 쓴 결과가 아니라, 일반 개발자가 현재 CLI를 실행할 때의 동작을 측정한 것이다.
테스트 저장소는 의도적으로 작고, 의도적으로 취약하게 만들었다. 9줄 안에 결함 네 가지를 심었다.
const express = require('express');
const { exec } = require('child_process');
const db = require('./db');
const app = express();
const API_KEY = "sk-live-9f3a2b7c1d4e5f6a8b9c0d1e2f3a4b5c";
app.get('/u', (req, res) => db.query("SELECT * FROM users WHERE id = " + req.query.id, (e, r) => res.json(r)));
app.get('/ping', (req, res) => exec("ping -c 1 " + req.query.host, (e, o) => res.send(o)));
app.get('/f', (req, res) => res.sendFile(__dirname + "/files/" + req.query.name));
app.listen(3000);
문자열 결합으로 만든 SQL, 쿼리 파라미터를 그대로 받는 child_process.exec, 정제하지 않은 sendFile 경로, 하드코딩된 키다. 환경은 macOS, Node v22.17.0, Python 3.14.6, @openai/[email protected], 번들 플러그인 0.1.14였으며, 모든 실행은 2026-07-29 02:20~03:05 UTC 사이에 진행했다.
| 실행 | 대상 | 예산 | 중단 시점 | 소요 시간 | 캐시 입력 | 신규 입력 | 출력 | 발견 항목 |
|---|---|---|---|---|---|---|---|---|
| 1 | 전체 저장소, 표준 모드 | $1.00 | $1.46 | 3m23s | 1,092,608 | 121,396 | 10,300 | 0 |
| 2 | 전체 저장소, 표준 모드 | $6.00 | $6.03 | 8m33s | 6,654,720 | 331,330 | 34,946 | 0 |
| 3 | 작업 트리, 한 줄 diff | $3.00 | $3.06 | 9m46s | 2,035,712 | 240,448 | 28,120 | 0 |
| 4 | 전체 저장소, 완전한 프로젝트 | $8.00 | $8.54 | 8m00s | 7,299,840 | 634,419 | 57,223 | 0 |
| 5 | 전체 저장소, reasoning_effort=low | $3.00 | $3.20 | 4m13s | 1,749,248 | 366,841 | 16,269 | 0 |
달러 금액은 스캔 도중 표시되고 scans list에 저장되는 CLI 자체 추정치다. 엔드포인트가 실제로 청구하는 금액이 아니라 OpenAI 정가와 토큰 수를 기준으로 계산하며, 토큰 수에 비해 총액이 낮아 보이는 이유는 캐시 입력 때문이다. 실행 2는 신규 입력 100만 토큰당 $5.00, 캐시 입력 100만 토큰당 $0.50, 출력 100만 토큰당 $30.00으로 정확히 계산된다.
331,330 x $5.00/M = $1.657
6,654,720 x $0.50/M = $3.327
34,946 x $30.00/M = $1.048
------
$6.032 (CLI reported $6.03239)
이 세 가지 요금은 다섯 번의 실행 총액을 모두 센트 단위까지 재현한다. 직접 돌린 수치가 이상해 보일 때 유용한 검산 기준이다.
다섯 번 모두 끝까지 완료되지는 못했다. 전부 예산 한도에서 중단됐으며, scans list에는 각각 phase: preflight, status: failed, coverage: worklistRows 0으로 표시됐다. 어느 실행도 취약점을 보고하는 단계까지 도달하지 못했다는 뜻이다.
실행 4는 대조군이다. 처음 만든 저장소는 의도적으로 불완전했다. package.json이 없고 ./db를 import하지만 실제 모듈은 없었는데, 도구가 작성한 위협 모델도 이를 명시적인 미확인 항목으로 지적했다. 의존성을 선언한 4개 파일, 13줄의 완전한 프로젝트로 다시 구성했더니 비용은 줄기는커녕 $8.54와 입력 토큰 790만 개까지 늘었다.
비용 증가 곡선은 선형이 아니다. 처음 3분 동안은 천천히 늘다가 두 차례 계단식으로 뛰는데, 각 구간은 에이전트가 작업 범위를 넓히는 시점과 맞물린다. 로그는 51초에 이 동작 원리를 한 번 알려준다. Preflight: worker delegation supported (up to 8 worker slots).
입력 토큰의 95%는 캐시 읽기였다. 같은 컨텍스트를 새로 읽기보다 매 턴마다 다시 전송했다는 의미다. 토큰당 단가는 낮지만 청구서에서는 가장 큰 항목이 됐다. 9줄짜리 파일을 대상으로 해도 캐시 입력 요금으로 700만 토큰이 쌓이면 금액은 커진다.
그래서 널리 반복되는 코드 1,000줄당 약 $0.02라는 추정은 여기서 무너진다. 그 계산이라면 이 저장소의 비용은 1센트보다 훨씬 작아야 했다.
추론 강도를 낮춰도 기대만큼 줄지 않는다
실행 5는 실행 4와 같은 프로젝트에서 model_reasoning_effort="low"를 설정했다. 토큰 소비량은 분당 약 100만 개에서 50만 개로 줄었으므로, 같은 금액으로 벽시계 기준 실행 시간은 두 배가 된다. 하지만 결과를 보고할 것 없이 여전히 preflight 단계에서 한도에 닿았다. 파이프라인이 예산 안에서 감당할 수 있는 것보다 더 많은 턴을 요구한다면, 소모 속도를 절반으로 낮춰도 해결되지는 않는다.
--max-cost는 브레이크가 아니라 체크포인트다
공식 CLI 문서는 이미 진행 중인 요청은 한도를 넘어서 완료될 수 있다고 설명한다. 다만 어느 정도까지 초과할 수 있는지는 밝히지 않는다. 다섯 번의 실행에서 초과 폭은 0.5%~46%였다. $1.00 한도는 $1.46에서, $6.00 한도는 $6.03에서 멈췄으며, 중간 세 개 한도는 2%~7%를 초과했다. 초과분은 에이전트가 이미 진행 중이던 작업량과 같다. 한도 근처에서 워커가 한꺼번에 확장되는 경우가 가장 비싸다. 절대 넘을 수 없는 금액보다 낮게 한도를 설정해야 한다.
pre-commit은 저렴한 우회로가 아니다
전체 스캔 비용이 과도하다면 바뀐 부분만 검사하는 것이 당연한 해법처럼 보인다. 깨끗한 기준 상태를 커밋한 뒤, 문자열 결합으로 만든 LIKE 절이라는 취약한 한 줄을 추가하고 --working-tree --base HEAD를 실행했다.
결과는 첫 전체 스캔보다 비쌌다. 9m46s가 걸렸고 입력 토큰 2,276,160개를 쓴 뒤, $3.00 한도에서 $3.06에 중단됐다. 전체 스캔보다 파이프라인을 더 진행해 순위가 매겨진 검토 작업 목록(rank_input.jsonl, deep_review_input.jsonl)까지 만들었지만, 취약점은 하나도 내놓지 못했다. diff로 범위를 좁혀도 턴당 컨텍스트가 작아지는 것은 아니다. 에이전트는 여전히 저장소를 읽고, 전체 위협 모델을 작성하며, 워커를 확장한다.
install-hook은 이를 Git pre-commit hook에 연결하며, 심각도가 높은 발견 항목과 스캔 오류가 있으면 커밋을 막는다. 팀에 설치하기 전에는 반드시 자기 코드베이스에서 diff 스캔 한 번의 비용부터 측정해야 한다. 커밋마다 몇 분과 몇 달러를 더할 수 있는 훅이기 때문이다.
아직 이 도구가 볼 수 없는 영역
이 도구가 9줄을 바탕으로 작성한 위협 모델은 완성도가 높다. 네 가지 신뢰 경계를 모두 식별했고, 누락된 ./db 모듈을 명시적인 미확인 항목으로 분류했으며, 검증할 수 없는 보호 기능을 Express가 제공한다고 가정하지 않았다. 스스로의 한계도 분명히 적어 뒀다. "Controls not present in the repository must not be assumed."
이것이 구조적 제약이다. 입력은 소스 코드뿐이므로 배포 시점에 결정되는 항목은 보이지 않는다. CORS 정책, 켜진 채 방치된 디버그 모드, 약한 TLS, 누락된 보안 헤더, 캐시 포이즈닝, 서비스 간 런타임 인가가 여기에 속한다. 특히 객체 수준 인가 결함은 실제 서로 다른 두 사용자로 인증 요청을 보내야 확인할 수 있는데, 소스 코드를 읽는 것만으로는 이를 제공할 수 없다.
언어별 분석 깊이도 균일하지 않다는 보고가 있다. 호스팅 서비스 사용 경험을 정리한 한 글에 따르면 Python, JavaScript, TypeScript, Go, Java 지원이 가장 강하고 Ruby, PHP, Kotlin은 그보다 뒤처진다. 이번 테스트는 JavaScript만 대상으로 했으므로 이 내용은 참고 정보로 봐야 한다.
그래서 지금 실행해야 할까?
위협 모델이 필요하다면 지금 설치할 만하다. 다섯 번의 실행에서 매번 받은 유일한 산출물이 바로 이것이었다. 신뢰 경계를 매핑하고, 공격자 시나리오를 나열하며, 이 서비스에서 critical·high·medium·low가 무엇을 뜻하는지 정의한 1,605단어 문서다. --knowledge-base는 자체 아키텍처 문서를 받을 수 있고 생성된 모델도 편집할 수 있으므로, 다른 보안 도구와 함께 쓸 입력 자료로도 유용하다.
예측 가능한 지출이나 실제 발견 항목 목록이 필요하다면 기다리는 편이 낫다. 다섯 가지 구성에서 10초면 읽을 수 있는 저장소를 대상으로 실행당 $1.46~$8.54를 썼지만, 둘 다 얻지 못했다. 파이프라인 뒤쪽에서 문서화된 산출물인 findings.json, coverage.json, report.md에도 도달하지 못했다. 권한이 부여된 ChatGPT Business 계정에서는 다르게 동작하는지가 이 테스트로는 답할 수 없는 열린 질문이다.
여기서는 대표적인 비용 절감 수단 두 가지가 모두 통하지 않았다. diff 범위 지정과 낮은 추론 강도는 결국 같은 벽에서 멈췄다. 계산을 실제로 바꾸는 요소는 모델 요금이다. 추정 비용은 정가 기준 토큰 수로 계산되므로, 정가 절반의 엔드포인트라면 같은 실행 비용도 절반이 된다. 저장소 크기가 아니라 실측 실행 결과로 예산을 잡고, 실제로 넘을 수 없는 한도보다 워커 한 라운드만큼 낮게 상한을 정하자. 이번 테스트에서 가장 큰 초과 폭은 한도의 46%였다.
FAQ
Codex Security CLI는 무료인가?
CLI와 SDK는 Apache-2.0 라이선스이며 설치 비용은 없다. 하지만 스캔은 무료가 아니다. 인증에 사용한 자격 증명에 따라 GPT-5.6 Sol 토큰이 소비되며, CLI는 OpenAI 정가 기준의 실행 중 추정 비용을 표시한다.
ChatGPT Business 또는 Enterprise 플랜이 필요한가?
호스팅형 GitHub 연동에는 필요하다. 이 경로는 Pro, Enterprise, Business, Edu로 제한된다. CLI는 일반 OPENAI_API_KEY를 받을 수 있지만, 문서는 전체 저장소 스캔에 Trusted Access for Cyber가 여전히 필요할 수 있다고 경고한다. 어떤 플랜도 이 권한을 자동으로 주지는 않는다.
CI에서 실행할 수 있나?
가능하다. OPENAI_API_KEY를 설정하고, 발견 항목이 있을 때 0이 아닌 종료 코드를 반환하도록 --fail-on-severity를 추가한 뒤, CODEX_SECURITY_STATE_DIR를 저장소 밖의 쓰기 가능한 경로로 지정하면 된다. 기본적으로 스캔은 보고만 수행한다.
서드파티 OpenAI 호환 엔드포인트에서도 작동하나?
엔드포인트가 Responses API를 구현한다면 가능하다. OPENAI_API_KEY만 설정하면 인증에 실패하므로, --codex 플래그로 Codex 프로바이더 설정을 덮어써야 한다.
CLI와 Codex Security plugin의 차이는 무엇인가?
스캔 엔진은 같고 진입점이 다르다. plugin은 연결된 GitHub 저장소를 대상으로 OpenAI 인프라에서 실행된다. CLI는 로컬 경로를 대상으로 사용자 머신에서 실행하며, 로컬 상태 디렉터리에 스캔 기록을 보관한다. 여기에 diff 범위 스캔, pre-commit hook, SARIF 내보내기, MCP 등록 기능이 더해진다.
관련 글: GPT-5.6 pricing guide · Codex auto mode
