보안 엔지니어로 일하면서 늘 하나의 질문이 머릿속에 있었다.
"내가 매일 쓰는 브라우저로 웹 서핑하는 그 트래픽 자체를 분석하면, 실제로 취약점이 보일까?"
Burp Suite를 켜고, 타겟을 설정하고, 스코프를 잡고, 리피터로 요청을 하나하나 뜯어보는 전통적인 방식. 물론 강력하다. 하지만 그건 "테스트를 하겠다"고 마음먹은 순간에만 작동하는 방식이다. 나는 그냥 평소에 웹 서핑하다가, 뉴스를 보다가, 쇼핑몰을 둘러보다가 — 그 흐름 그대로 취약점을 발견할 수 있으면 어떨까 하는 생각이 들었다.
그래서 만들어봤다. LLM-HOOK-BROWSER.
이미 나는 dmass라는 LLM 기반 자동화 보안 스캐너를 만들어 운영하고 있었다. dmass는 꽤 정교한 도구다. SQLi 5단계 탐지, SSTI 8개 엔진별 핑거프린팅, JWT 7가지 공격 벡터, WAF 벤더별 우회 전략, OOB 콜백 서버까지 — 본격적인 침투 테스트를 위한 풀스택 스캐너다.
그런데 dmass는 "스캔을 실행한다"는 행위가 전제된다. 타겟 URL을 넣고, 스코프를 정의하고, 프로필을 선택해서 돌린다. 이건 업무용이다.
내가 원했던 건 달랐다. 의식하지 않아도 작동하는 보안 센서. 내 브라우저가 곧 스캐너가 되는 것.
dmass에서 검증된 탐지 알고리즘들 — SQL 에러 시그니처 20여 종, NoSQL 연산자 인젝션 패턴, 컨텍스트별 XSS 페이로드, 클라우드 메타데이터 프로빙, CVSS v3.1 계산 공식 — 이것들을 가져와서, 브라우저 프록시 위에 얹으면 어떨까?
구조는 단순하다.
크롬 브라우저 (프록시 설정)
↓
mitmproxy (HTTPS 트래픽 복호화)
↓
2단계 분석 파이프라인
├── Stage 1: 알고리즘 사전분석 (패턴 매칭)
└── Stage 2: Claude Sonnet 정밀분석
↓
실시간 대시보드
크롬을 프록시 모드로 띄우면, 내가 방문하는 모든 사이트의 HTTP/HTTPS 트래픽이 mitmproxy를 통과한다. 여기서 SecurityInterceptor가 의미 있는 요청(POST, 쿼리 파라미터가 있는 GET 등)을 골라서 DB에 저장한다.
저장된 각 요청은 2단계 파이프라인을 거친다.
LLM을 호출하기 전에, 20개의 패턴 매칭 검사기가 먼저 빠르게 스캔한다.
이 단계는 밀리초 단위로 끝난다. 여기서 나온 힌트들은 다음 단계의 LLM에게 "이쪽을 집중해서 봐"라는 가이드가 된다.
Claude Sonnet이 HTTP 트랜잭션 전체(요청 헤더, 바디, 응답 헤더, 바디)를 읽고, 35개 취약점 카테고리에 대해 정밀하게 판단한다. 단순히 "취약점이 있다/없다"가 아니라:
사전분석의 힌트와 LLM의 판단을 신뢰도 병합 공식으로 결합한다. 둘 다 독립적으로 탐지했으면 신뢰도가 올라가고, 한쪽만 탐지했으면 적절히 가중된다.
샘플사이트를 타겟으로 설정하고, 크롬으로 평소처럼 사이트를 둘러봤다. 메인 페이지를 보고, 몇 개 상품을 클릭하고, 검색을 해봤다. 특별한 공격 시도 없이, 그냥 일반 사용자처럼.
18개 요청이 캡처되었고, 33개 취약점이 발견되었다.
| 심각도 | 건수 | 발견 내용 |
|---|---|---|
| MEDIUM | 12 | IDOR/BOLA (예측 가능한 stayId), Insecure Cookies, Security Header 누락 |
| LOW | 14 | CORS 설정 이슈, Sentry DSN 노출, 내부 메타데이터 노출 |
| INFO | 7 | 보안 헤더 미설정 |
흥미로웠던 것들:
1. IDOR/BOLA 가능성 — URL에 순차적 정수 ID(xxxId)가 노출되어 있어서, ID를 변경하면 다른 상품의 비공개 정보에 접근할 수 있는지 추가 검증이 필요한 상태.
2. Sentry DSN 공개키 노출 — Cloudflare RUM 요청 헤더에 Sentry DSN이 포함되어 있었다. 공개키 자체는 치명적이지 않지만, 내부 프로젝트 구조를 유추할 수 있는 정보.
3. 세션 쿠키 보안 속성 — 테스트사이트의 sid 쿠키에 HttpOnly, Secure, SameSite 속성이 불완전할 가능성이 탐지됨.
4. CORS with Credentials — Origin 반영 동작이 감지되어, 악의적 사이트에서 인증된 요청을 보낼 수 있는지 추가 확인 필요.
이 모든 게 그냥 웹 서핑만 했을 뿐인데 나온 결과다.
dmass의 attack playbook에서 가져온 페이로드 데이터베이스가 내장되어 있다.
취약점이 발견되면, 이 페이로드 DB에서 적절한 것을 선택해 LLM에게 "이런 페이로드로 검증해봐"라고 제안하고, 안전한 시뮬레이션을 실행할 수 있다.
모든 취약점에 CVSS v3.1 점수가 자동 산출된다. dmass의 CVSS 계산기를 그대로 포팅했다.
SQL Injection → CVSS 9.8 (Critical)
SSRF → CVSS 8.6 (High)
SSTI → CVSS 9.8 (Critical)
JWT alg:none → CVSS 9.1 (Critical)
IDOR → CVSS 7.1 (High)
XSS → CVSS 6.1 (Medium)
LLM이 CVSS 벡터를 직접 제시하면 그걸 쓰고, 아니면 취약점 유형에 매핑된 기본 벡터로 계산한다. 30개 이상의 취약점 유형에 대한 기본 벡터가 내장되어 있다.
mitmproxy 11은 자체 이벤트 루프를 요구하는데, FastAPI(uvicorn)도 자체 루프를 돌린다. 별도 스레드에서 mitmproxy를 돌리되, DumpMaster에 이벤트 루프를 명시적으로 주입하는 방식으로 해결했다.
처음에는 응답 본문에서 /usr/bin/ 같은 경로가 보이면 Command Injection으로 잡았는데, 일반 HTML 페이지에서도 이런 문자열이 나올 수 있다. 요청에 공격 패턴이 없으면 응답에서만 탐지된 결과는 무시하도록 수정했다. "입력에 원인이 있어야 출력의 결과를 의심한다"는 원칙.
AWS Bedrock을 쓰는데, 일반적인 AWS Signature V4가 아닌 Bearer Token 방식이었다. Anthropic SDK가 이걸 직접 지원하지 않아서, httpx로 Bedrock REST API를 직접 호출하는 경로를 추가했다.
사전분석(알고리즘)과 LLM이 독립적으로 판단한 신뢰도를 어떻게 합칠 것인가? 단순 평균이 아니라, 독립 사건의 결합 확률 공식을 사용했다:
merged = 1 - (1 - conf_llm) × (1 - conf_pre)
둘 다 0.8이면 0.96으로 올라간다. 한쪽이 0이면 다른 쪽 값 그대로. 직관적이면서도 수학적으로 타당하다.
솔직히 말하면, 이 도구를 만드는 데 걸린 시간은 놀라울 정도로 짧았다.
dmass에서 검증된 알고리즘이 있었고, LLM이 복잡한 프롬프트 엔지니어링을 대신 소화해줬고, mitmproxy라는 훌륭한 오픈소스가 HTTPS 인터셉트를 해결해줬다. 내가 한 것은 이것들을 "내 브라우저로 서핑하면서 취약점을 찾고 싶다"라는 하나의 아이디어로 연결한 것뿐이다.
우리는 지금 일상의 아이디어가 하루 만에 동작하는 도구가 되는 시대에 살고 있다.
"이거 되면 좋겠다"라는 생각이 드는 순간, 그걸 실제로 만들어볼 수 있는 환경이 갖춰져 있다. LLM이 코드를 짜고, 오픈소스가 인프라를 제공하고, 클라우드가 컴퓨팅을 댄다. 우리에게 필요한 건 딱 하나 — "이거 해보면 어떨까?"라는 호기심이다.
그 호기심을 코드로 옮기는 속도가, 지금 이 시대가 우리에게 준 가장 강력한 무기다.
보안이든, 데이터든, 자동화든 — 당신이 매일 하는 일에서 "이거 자동으로 되면 좋겠다"라고 느끼는 그 순간이 있다면, 그게 다음 도구의 시작점이다. 더 이상 "나중에"가 아니라 "지금 바로" 시도해볼 수 있다.
내 브라우저가 취약점 스캐너가 된 것처럼, 당신의 일상 도구도 무언가 더 될 수 있다.