AI가 생성한 Python 코드에서 하드코딩된 자격 증명
요약
AI가 생성한 Python 코드가 하드코딩된 자격 증명(credentials)을 포함하는 보안 취약점을 발견했습니다. 이는 모델이 '실행 가능한 예제'를 요청받았기 때문에, 환경 변수 사용 지침 없이도 실제 작동하는 값을 채워 넣는 프롬프트 완성 과정에서 발생합니다. 해결책은 자격 증명을 환경 변수로 이동시키는 것입니다.
핵심 포인트
- AI 코드는 실행 가능성을 위해 하드코딩된 비밀을 포함할 수 있습니다.
- 이는 모델의 부주의함이 아닌, 프롬프트 완성 역동성 때문입니다.
- 자격 증명 관리는 소스 파일 변경 및 재배포가 필요합니다.
- 해결책은 자격 증명을 환경 변수(environment variable)로 이동시키는 것입니다.
BrassCoders는 자체 공개 벤치마크 코퍼스에 포함된 15개의 AI 생성 Python 파일 중 2개에서 하드코딩된 자격 증명을 발견했습니다. token_check.py는 리터럴 HMAC 서명 키를 내장했고, email_sender.py는 평문 SMTP 비밀번호를 내장했습니다. 두 파일 모두 현실적인 프롬프트로부터 생성되었습니다. 이 파일들 중 어느 것도 보안하게 시크릿을 처리하도록 요청받지 않았습니다.
AI가 생성한 코드가 자격 증명 유출을 일으키는 방식은 부주의함 때문이 아니라, 프롬프트 완성(prompt completion) 과정 때문입니다.
token_check.py의 HMAC 키
BrassCoders는 하드코딩된 시크릿 때문에 token_check.py를 플래그 지정했습니다. 이 파일은
BrassCoders는 하드코딩된 비밀번호 때문에 email_sender.py를 플래그 지정했습니다. 이 파일은 'SMTP를 통해 사용자에게 템플릿화된 환영 이메일을 보내는 함수 작성'이라는 프롬프트로부터 생성되었으며, 모델은 실제 비밀번호가 포함된 작동하는 SMTP 로그인을 작성했습니다.
관련 라인은 다음과 같습니다:
with smtplib.SMTP("smtp.example.com", 587) as server:
server.starttls()
server.login("noreply@example.com", "hunter2-mailpassword")
...
"hunter2-mailpassword"는 server.login()의 실제 두 번째 인자입니다. 이는 소스 파일에 포함되어 SMTP 서버로 직접 전달됩니다. 이 함수를 프로덕션 환경에서 사용하는 개발자는 코드를 받는 모든 환경에 자신의 SMTP 자격 증명을 노출하게 됩니다. 자격 증명 로테이션(Credential rotation)은 비밀 관리자(secrets manager)에서 자격 증명을 회전시키는 것이 아니라 소스 파일을 변경하고 재배포하는 것을 의미합니다.
Bandit의 B106 규칙은 함수 인자에 전달되는 값 중 자격 증명 관련 매개변수 이름을 포함하는 하드코딩된 값을 플래그 지정합니다. BrassCoders는 이를 detect-secrets의 엔트로피 분석과 함께 제시하므로, 두 스캐너에서 동일한 결과로 해당 취약점이 나타납니다.
모델이 자격 증명을 포함하는 이유
프롬프트는 '실행 가능한 예제'를 요청했습니다. 사용 가능한 HMAC 예제에는 키가 필요합니다. 사용 가능한 SMTP 예제에는 자격 증명이 필요합니다. 따라서 모델은 로컬 컴퓨터에서 오류 없이 실행되도록 만드는 값을 채워 넣습니다. 환경 변수나 비밀 관리자를 사용하라는 지침이 프롬프트에 없었기 때문에, 모델은 이를 추가하지 않습니다.
이것이 코드에 자격 증명을 생성하는 프롬프트-완성(prompt-completion) 역동성입니다. 모델이 더 잘 알지 못해서 보안에 취약한 코드를 생성하는 것이 아닙니다. 명시된 요구 사항을 충족시키는 코드를 생성하고 있는 것입니다. 비밀 관리자 통합을 명시적으로 요청하는 프롬프트를 사용하면 그 대신 그것을 생성합니다. 대부분의 프롬프트는 그렇지 않습니다.
Veracode가 AI 생성 코드에 대한 2025년 분석에서 AI 생성 코드의 45%가 최소한 하나의 OWASP Top 10 취약점을 가지고 있는 것을 발견했으며, 자격 증명 노출은 가장 흔한 유형 중 하나입니다.
해결 방법
두 발견 사항 모두 동일한 해결책을 가지고 있습니다. 자격 증명을 환경 변수(environment variable)로 이동하는 것입니다.
token_check.py의 경우:
import os
SECRET_KEY = os.environ["HMAC_SECRET_KEY"]
이제 키가 소스 파일에 존재하지 않습니다. 런타임(runtime)에서 환경 변수를 통해 주입됩니다. 버전 관리 시스템(Version control)에는 포함되지 않고, 빌드 아티팩트(build artifacts)에도 포함되지 않으며, 코드 변경 없이 키를 순환(rotate)할 수 있습니다.
email_sender.py의 경우:
smtp_password = os.environ["SMTP_PASSWORD"]
server.login("noreply@example.com", smtp_password)
BrassCoders는 발견 사항마다 해결(remediation) 메모를 출력합니다. Claude Code는 "하드코딩된 자격 증명을 환경 변수 읽기로 대체하라"라는 내용을 읽고 플래그가 지정된 줄에서 os.environ 버전을 생성합니다.
발견 사항 재현하기
git clone https://github.com/CopperSunDev/brasscoders
pip install brasscoders
brasscoders --offline scan brasscoders/docs/benchmarks/ai-code-findings-corpus/files
token_check.py와 email_sender.py의 하드코딩된 자격 증명 발견 사항은 심각도(severity)가 high, 파일 경로, 줄 번호 및 환경 변수 해결책과 함께 .brass/ai_instructions.yaml에 나타납니다. 실행할 때마다 동일한 출력이 나옵니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기