당신의 AI는 보안 정책을 알지 못합니다
요약
AI 어시스턴트가 조직의 보안 정책이나 비밀 정보 관리 컨벤션을 인지하지 못해 발생하는 '정책 격차(Policy gap)' 문제를 다룹니다. AI가 생성한 코드에 하드코딩된 자격 증명이 포함될 위험성을 실제 사례를 통해 경고합니다.
핵심 포인트
- AI는 조직의 내부 보안 표준이나 비밀 정보 관리 맥락을 알지 못함
- 정책 격차로 인해 AI 생성 코드에 하드코딩된 자격 증명이 포함될 수 있음
- 바이브 코딩(Vibe-coding) 시 수동 검토 생략으로 인한 보안 사고 위험 증가
- AI 생성 코드 내 자격 증명 포함 사례(HMAC 키, SMTP 비밀번호 등) 확인
AI 어시스턴트는 당신이 HashiCorp Vault를 사용하고 있다는 사실을 모릅니다. 당신의 팀이 지난 분기에 모든 비밀 정보(Secrets)를 AWS Secrets Manager에 저장하기로 합의했다는 사실도 모릅니다. 당신의 .env 컨벤션, CI/CD 주입 패턴, 또는 로테이션 정책(Rotation policy)도 모릅니다. AI가 아는 것은 단 하나뿐입니다: 당신이 프롬프트(Prompt)를 주었고, 그 프롬프트에는 값을 기대하는 필드가 있다는 사실입니다.
그래서 AI는 값을 채워 넣습니다.
이것이 바로 정책 격차(Policy gap)입니다. 이것은 환각(Hallucination) 버그나 모델 정렬(Model alignment) 문제가 아닙니다. 구조적인 문제입니다. 모델은 눈앞에 있는 내용을 완성할 뿐이며, 모델의 눈앞에 있는 내용에는 비밀 정보 관리(Secrets-management)에 대한 맥락이 부착되어 있지 않습니다.
정책 격차 (The Policy Gap)
BrassCoders는 자연스럽게 생성된 AI Python 코드의 공개 코퍼스(Corpus) 중 15개 파일 중 2개 파일에서 하드코딩된 자격 증명(Hardcoded credentials)을 발견했습니다. 이 파일들은 문제를 심거나 피하려는 시도 없이 현실적인 프롬프트로부터 생성된 파일들입니다. 모델은 적절해 보이는 것을 채워 넣었습니다. 두 파일 모두 개발자가 화요일 오후에 AI 어시스턴트에게 보낼 법한 프롬프트에서 생성되었습니다.
15개 중 2개라는 비율은 재앙 수준은 아닙니다. 하지만 이는 기준점(Baseline)입니다. 이는 몇 가지 유틸리티 스크립트를 생성하는 전형적인 바이브 코딩(Vibe-coding) 세션에서, 적어도 하나는 그곳에 있어서는 안 될 자격 증명을 포함할 가능성이 높다는 것을 알려줍니다. 수동 검토(Manual review)라면 이를 잡아낼 수 있었을 것입니다. 하지만 바이브 코딩은 정의상 검토 단계를 건너뜁니다.
조직적 복합 요인: 당신의 AI 어시스턴트는 당신의 내부 표준에 대한 지식이 없습니다. AI에게 "환경 변수(Environment variables)를 사용하라"고 프롬프트를 주는 것은 해당 파일 하나에는 도움이 됩니다. 하지만 그 효과가 다음 파일이나 다음 개발자, 또는 다음 AI 세션으로 이어지지는 않습니다. 누군가 새로운 채팅을 시작할 때마다 정책 격차는 다시 발생합니다.
N=15 코퍼스에서 발견된 내용
BrassCoders는 15개의 AI 생성 Python 파일을 스캔했습니다. 전체 코퍼스는 coppersun.dev/benchmarks에 공개되어 있으며 고정된 소스(Pinned source)를 통해 재현 가능합니다. 두 개의 파일에는 하드코딩된 자격 증명이 포함되어 있었으며, 두 파일 모두 패턴 매칭(Pattern matching)만으로 탐지할 수 있었습니다.
token_check.py에는 SECRET_KEY = "s3cr3t-signing-key-change-me" — 즉, 실제 HMAC 서명 키(HMAC signing key)가 포함되어 있었습니다. 프롬프트는 세션 토큰(session token)을 서명하고 검증하는 함수를 요청했습니다. 모델은 작동하는 HMAC 코드를 생성했습니다. 또한 코드가 실행되는 데 키가 필요하기 때문에 서명 키도 함께 생성했습니다.
email_sender.py에는 server.login("noreply@example.com", "hunter2-mailpassword") — 즉, 로그인 호출에 임베디드된 실제 SMTP 비밀번호가 포함되어 있었습니다. 프롬프트는 이메일 전송 함수를 요청했습니다. SMTP 로그인은 비밀번호를 필요로 합니다. 모델은 이를 제공했습니다.
두 사례 모두 교과서적인 완성(completions)입니다. 모델은 자격 증명(credential)이 필요한 코드 패턴을 보고 자격 증명을 제공합니다. 두 파일 모두 예제 코드(example code)로 표시되거나 초안(draft)이라고 명확하게 라벨링되지 않았습니다. 빠르게 작업 중이라면 두 파일 모두 육안 검사(visual scan)를 쉽게 통과할 것입니다.
상세한 코퍼스 워크스루(corpus walkthrough)는 동반 포스트에서 확인하실 수 있습니다 — 각 파일에 대한 정확한 스캐너 출력 결과를 보고 싶다면 그곳부터 시작하는 것이 좋습니다.
BrassCoders가 감시하는 20개 이상의 형식
BrassCoders는 Yelp의 detect-secrets를 업스트림 라이브러리(upstream library)로 사용하여 20개 이상의 비밀 형식을 탐지하며, 여기에 BrassCoders의 스캐너 레이어(scanner layer)에 추가된 7개의 커스텀 패턴(custom patterns)을 더합니다. 이 조합은 AI가 생성한 코드에서 가장 자주 나타나는 자격 증명 유형을 포괄합니다.
Yelp의 detect-secrets는 AWS 액세스 키(AKIA 접두사), GitHub PATs(ghp_), Stripe 라이브 키(sk_live_), OpenAI 키(sk-), Slack 토큰, PEM 형식의 개인 키(private keys), JWT, 그리고 알려진 형식과 일치하지 않는 고엔트로피 문자열(high-entropy strings)을 처리합니다. 커스텀 레이어는 detect-secrets가 기본적으로 다루지 않는 패턴을 추가로 탐지합니다.
이들이 다루지 못하는 것: 조직 내부에서 정의한 비밀 정보(secrets) — 커스텀 API 토큰 형식, 독자적인 서명 체계(proprietary signing schemes), 알려진 구조적 패턴을 따르지 않는 모든 것들입니다. 이는 반드시 알아두어야 할 공백입니다. BrassCoders의 YAML 출력은 각 탐지 항목을 어떤 스캐너가 플래그(flag)했는지 이름을 명시하므로, 커버리지를 감사하고 기본 세트 이외의 형식에 대해 .brassignore 항목을 추가하거나 상위 Semgrep 규칙을 추가할 수 있습니다.
How BrassCoders catches hardcoded secrets는 엔트로피 점수 산정(entropy scoring), 형식 매칭(format matching), 그리고 스캐너가 오탐(false positives)의 경계선을 어디에 두는지 등 탐지 메커니즘 전체를 다룹니다.
플레이스홀더(Placeholder)가 실제 키만큼 위험한 이유
BrassCoders는 SECRET_KEY = "s3cr3t-signing-key-change-me"를 실제 자격 증명(credential)과 동일한 방식으로 플래그합니다. OWASP A02:2021 (암호화 실패 (Cryptographic Failures))는 이 둘을 구분하지 않기 때문입니다. 만약 여러분이 "교체할 시간을 내는 동안" 단 일주일이라도 운영 환경에서 해당 값을 사용한다면, 보안 경계는 무너진 것입니다.
Git 히스토리는 잊지 않습니다. 자격 증명 문자열이 커밋(commit)에 한 번 나타나면, 누군가 의도적으로 히스토리 재작성(history rewrite)을 실행하기 전까지 저장소의 히스토리에 남게 됩니다. 빠르게 움직이는 팀들은 몇 달이 지나서야 해당 커밋을 알아차리는 경우가 많습니다. 그때쯤이면 자격 증명은 백업 스냅샷, CI 로그, 또는 해당 브랜치를 풀(pull)한 모든 사람의 IDE 히스토리에 남아있을 수 있습니다.
조직적인 압박은 상황을 더 악화시킵니다. 실제 값처럼 보이는 플레이스홀더는 SECRET_KEY = "REPLACE_ME"와 같은 것만큼 경보를 울리지 않습니다. PR을 읽는 개발자는 그것이 의도적으로 설정된 것처럼 보이는 것을 보게 됩니다. 그리고 그대로 통과됩니다.
이것이 더 광범위한 비밀 정보 처리 방식에서 실제 자격 증명과 플레이스홀더 자격 증명을 모두 다루는 이유입니다. 어떤 경우든 로테이션(rotation) 워크플로우는 동일합니다. 그것을 로테이션하고, 교체한 다음, 메모와 함께 해당 파일을 .brassignore에 추가하십시오. 플레이스홀더가 가짜처럼 보인다고 해서 안전하다고 가정하지 마십시오.
조직적 해결책: 첫 번째 커밋 전의 비밀 정보 관리 (Secrets Management)
BrassCoders는 프롬프트 계층(prompt layer)이 할 수 없는 일을 도구 계층(tool layer)에서 수행하여 정책 격차를 해소합니다. AI 어시스턴트에게 환경 변수(environment variables)를 사용하라고 프롬프팅하는 것은 정책이 아닙니다. 그것은 다음 개발자가 새로운 채팅 세션을 열 때 증발해 버리는 조언일 뿐입니다.
실제로 작동하는 구체적인 워크플로우는 다음과 같습니다:
코드를 생성하기 전: 프로젝트에서 어떤 비밀 정보 관리자(secrets manager)를 사용하는지 결정하십시오. AWS Secrets Manager, HashiCorp Vault, python-dotenv로 로드되는 .env 파일, 또는 CI/CD 플랫폼의 네이티브 인젝션(native injection) 중 하나를 선택하십시오. 이를 README에 문서화하십시오. 한 줄이면 충분합니다.
모든 생성 세션이 끝난 후: 커밋하기 전에 brasscoders --offline scan을 실행하십시오. --offline 플래그는 외부 네트워크 호출을 전혀 하지 않습니다. 모든 스캐너는 로컬에서 실행되며, 아무것도 기기 외부로 나가지 않습니다. YAML 출력 결과에는 파일명, 줄 번호, 그리고 매칭된 패턴이 표시됩니다. 커밋이 반영되기 전에 이를 수정하거나 .brassignore에 추가하십시오.
탐지 결과가 나타났을 때: 자격 증명(credential)을 교체(rotate)하십시오. 해당 정보가 유출된 것으로 간주해야 합니다. 만약 해당 문자열이 테스트 픽스처(test fixture)라면, FIXTURE 표시가 된 명명 규칙으로 전환하십시오 (예: AKIAFIXTURE000000000, ghp_FIXTUREbcdef...). BrassCoders의 스캐너는 이를 실제 키가 아닌 테스트 아티팩트(test artifact)로 인식하도록 학습되었습니다.
매 커밋 전 2분간의 스캔은 바이브 코딩(vibe coding)이 제거해 버린 검토 단계를 의미합니다. BrassCoders는 생성 루프의 속도를 늦추지 않으면서도 이 단계를 다시 복구합니다.
PyPI에서 BrassCoders를 설치하십시오:
pip install brasscoders
brasscoders --offline scan .
계정 불필요. 텔레메트리(telemetry) 없음. Apache 2.0.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기