파이썬 AI 앱 보안 스캐너를 벤치마킹했습니다. 각 스캐너가 잡아내는 항목은 다음과 같습니다.

발행: (2026년 6월 5일 PM 10:12 GMT+9)
7 분 소요
원문: Dev.to

출처: Dev.to

onfafanutifafa

이번 주에 저는 Python AI‑앱 정규식 프리필터를 getdebug 0.4.0에 추가하고, 실제 Python 코드에 대해 Bandit과 Semgrep과 비교 벤치마크했습니다. 아래는 각 도구가 실제로 잡아내는 내용과 수치입니다.

네 가지 도구

Bandit (PyCQA) — Python OSS 표준 보안 린터. 직접 작성한 규칙, 무료, 빠름, Python 전용.

Semgrep — 커뮤니티 규칙 팩을 제공하는 다중 언어 SAST. 직접 작성한 규칙, 무료, 빠름.

vulnhuntr (Protect AI, 오픈소스) — LLM 기반 AI‑앱 정적 분석 분야의 선언된 카테고리 리더. Python 전용.

getdebug — JS/TS + Python에서 패턴 기반 정규식 프리필터(0.4.0에 새로 추가). 옵션으로 Ollama를 이용한 로컬 LLM SAST(무료, 디바이스 내)와 호스팅 서비스(유료) 제공.

테스트 1 — 취약/안전 피처 쌍

AI‑앱 카테고리별(피이 인 프롬프트, unsafe‑role‑merge, 프롬프트 인젝션, 무제한 스트림, unsafe‑tool‑output)로 10개의 직접 작성한 Python 피처를 준비했습니다. 각 카테고리마다 취약 버전 1개와 안전 버전 1개씩, 총 5쌍을 테스트했습니다.

Tool        TP  FP  FN   Precision  Recall
getdebug     5   0   0    100%       100%
bandit       1   1   4    50%        20%
semgrep      1   1   4    50%        20%
vulnhuntr    —   —   —    (완료 불가; 아래 참고)

Bandit과 Semgrep 모두 unsafe-tool-output 피처를 그들의 일반적인 subprocess.run(shell=True) 규칙으로 잡아냅니다. 이는 취약 버전에서는 True Positive가 되지만, 안전 버전에서도 동일한 규칙이 작동해 False Positive가 발생합니다.

# 안전 패턴 — Bandit + Semgrep 모두 FP로 표시함
ALLOWED = {"hosts": "cat /etc/hosts", "uptime": "uptime"}
def handle(tool_call):
    cmd = ALLOWED.get(tool_call.input.tag)
    if not cmd: return "rejected"
    return subprocess.run(cmd, shell=True, capture_output=True).stdout

두 도구는 cmd가 정적 딕셔너리에서 온 것이고 모델이 만든 것이 아니라는 사실을 알지 못합니다. shell=True만 보고 경고를 발생시키죠. 반면 getdebug의 정규식은 sink 인자에 tool_call.input.X 혹은 block.input.X와 같은 참조가 있어야만 매칭되도록 설계돼 있어, 위와 같은 allowlist‑then‑run 패턴은 깨끗하게 통과합니다.

두 도구는 나머지 네 가지 행동 카테고리(pii‑in‑prompt, unsafe‑role‑merge, prompt‑injection, unbounded‑stream)를 전혀 탐지하지 못합니다. 규칙 팩에 {"role": "system", "content": f"...{name}..."}와 같은 패턴이 포함돼 있지 않기 때문이며, 이것이 현재의 격차입니다.

테스트 2 — 실제 환경의 시그널/노이즈

세 도구(동작 가능한 것) 모두를 Simon Willison이 만든 LLM용 깔끔한 CLI인 simonw/llm 저장소(48개의 Python 파일) 에 적용해 보았습니다.

Tool        Total findings    Signal
bandit      1,189            1,158개가 'assert_used' (pytest) 경고;
                              AI‑앱 관련 탐지는 전무
semgrep     3                3개의 일반 SAST 히트;
                              AI‑앱 관련 탐지는 전무
getdebug    6                6개의 AI‑앱 탐지: 1개는 prompt‑injection,
                              5개는 unbounded‑stream

Bandit이 48개 파일에서 1,189개의 결과를 내놓은 대부분은 pytest assert_used 경고이며, 실제 프로젝트 설정에서는 보통 비활성화되는 항목입니다. Semgrep의 3개 결과는 실제이지만 AI‑앱과는 무관합니다. getdebug은 전부 AI‑앱에 해당하는 6개의 결과만을 반환했습니다.

vulnhuntr에 관하여

vulnhuntr는 해당 분야의 선언된 리더라고 합니다. 교차 검증을 시도했지만, 여러 문제로 진행하지 못했습니다.

  • --llm claude-code 모드(키 없이 실행)에서 1.2.2 버전이 ModuleNotFoundError로 크래시
  • --llm gptgpt-4o-mini 조합이 응답 검증 단계에서 pydantic validation 오류 발생
  • --llm gptgpt-4o 조합이 작은 계정에 대해 OpenAI 기본 30K TPM 제한에 걸림
  • 기본 파일 선택 휴리스틱이 “네트워크에 노출된” 엔트리 포인트를 찾도록 설계돼 있어, CLI 형태인 simonw/llm에서는 분석할 파일을 0개로 판단

스택이 2026년에 안정화되면 다시 벤치마크를 진행할 예정입니다.

여러분에게 의미하는 바

LLM을 호출하는 Python 코드를 배포한다면, 세 도구를 모두 실행하세요. 서로 보완적인 역할을 합니다.

bandit -r .                              # 일반 Python 위생 검사
semgrep --config auto .                  # 다중 언어 SAST 커버리지
npx @getdebug/cli@0.4.0 analyze .       # AI‑앱 행동 패턴 검사

어느 하나도 다른 두 도구를 대체하지 못합니다. 첫 두 도구는 일반적인 SAST를 잡아내고, getdebug은 “전체 사용자 객체를 프롬프트에 직렬화”하는 패턴처럼 일반 SAST 규칙으로는 지속적으로 작성하기 어려운 케이스를 포착합니다.

모든 수치는 getdebug.dev/bench에서 재현할 수 있습니다. 코퍼스와 방법론은 getdebug-ai/codesecbench에서 공개되어 있습니다.

전체 글은 여기서 확인하세요: https://www.getdebug.dev/blog/python-ai-app-prefilters

0 조회
Back to Blog

관련 글

더 보기 »

모바일 한여름 열풍

!Cover image for Mobile Midsommer Madnesshttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploa...