의존성 스캐너가 수백 건의 CVE를 알리면 팀은 두 가지 극단 사이에서 흔들리기 쉽습니다. 모두 즉시 고치려 하면 릴리스와 기능 개발이 멈추고, 너무 많은 항목을 “우리 코드에서는 안 쓴다”로 닫으면 실제 공격 경로를 놓칩니다. 특히 간접 의존성, 여러 container image, 오래된 feature flag, 에이전트가 만든 변경이 겹치면 패키지가 설치됐다는 사실만으로는 우선순위를 정하기 어렵습니다.
그래서 최근 취약점 운영의 관심은 취약점 목록을 더 길게 만드는 것보다 어느 artifact가 어느 runtime에서, 어떤 요청 경로로, 어떤 전제조건 아래 취약 코드를 실제로 도달할 수 있는지를 증거로 연결하는 쪽으로 옮겨가고 있습니다. 여기서 Runtime Reachability Evidence는 특정 상용 도구 이름이 아니라, SBOM·정적 분석·배포 provenance·runtime 관측·운영 완화책을 한 판단 레코드에 묶는 방식입니다. 이 글은 완화된 취약점 예외의 증거 관리, artifact attestation 기반 배포 gate, eBPF 관측 플랫폼 도입, AI 코드 출처와 SBOM 운영을 취약점 우선순위 관점에서 연결합니다.
이 글에서 얻는 것
- SBOM, SCA finding, 도달성, exploitability, business impact가 서로 다른 질문임을 구분할 수 있습니다.
- critical finding을 지연시키지 않으면서도 대량의 낮은 우선순위 알림을 증거 기반으로 정리하는 흐름을 설계할 수 있습니다.
- 정적 분석과 runtime 관측을 어떻게 조합하고, “관측되지 않음”을 왜 안전 판정으로 바꾸면 안 되는지 이해할 수 있습니다.
- 패치 예외를 만료되는 운영 결정으로 만들기 위한 evidence·owner·재검토 기준을 만들 수 있습니다.
핵심 개념/이슈
1) 설치됨, 호출 가능함, 공격 가능함은 같은 말이 아니다
SBOM과 SCA는 어떤 package와 버전이 artifact 안에 들어갔는지 확인하는 데 강합니다. 이는 공급망 inventory의 출발점입니다. 하지만 package가 들어 있다는 사실만으로 애플리케이션이 취약 함수에 도달하는지, 외부 공격자가 필요한 입력을 만들 수 있는지, 이미 있는 WAF·권한 검증·network policy가 어떤 위험을 줄이는지는 알 수 없습니다.
| 질문 | 필요한 증거 | 빠지면 생기는 오판 |
|---|---|---|
| 취약 구성요소가 배포됐는가 | image digest와 SBOM, package lock·manifest | 개발 환경의 finding을 운영 위험으로 과대평가 |
| 취약 code path를 호출할 수 있는가 | 정적 call graph, application route, dependency usage | 사용하지 않는 optional module에 같은 긴급도를 부여 |
| 외부에서 exploit 조건을 만들 수 있는가 | internet exposure, auth/tenant boundary, input validation | 내부 batch 경로와 public endpoint를 동일시 |
| 현재 완화책이 유효한가 | policy config, request trace, control test, owner 확인 | 과거에만 존재했던 방어를 현재도 있다고 가정 |
| 그래도 패치가 필요한가 | vendor guidance, known exploitation, 지원 종료, 영향 분석 | 도달성 낮음을 영구 면제로 오해 |
예를 들어 취약한 parser library가 container에 들어 있어도, 해당 기능이 feature flag 뒤에서 비활성화됐거나 오직 내부에서 서명된 파일만 받는 batch에 제한될 수 있습니다. 반대로 “우리 서비스는 parser API를 직접 호출하지 않는다”는 정적 검색 결과만 믿으면, framework adapter나 plugin이 외부 업로드 경로에서 그 library를 호출하는 사실을 놓칠 수 있습니다. 따라서 reachability는 true/false 하나보다 확인된 도달, 미확인, 현재 증거상 도달 불가, 관측 범위 밖처럼 불확실성을 드러내는 상태가 더 안전합니다.
2) runtime 관측은 판결문이 아니라 증거 한 조각이다
eBPF, application trace, profiler, audit log는 실제 process가 어떤 library·함수·endpoint를 사용했는지 보여줄 수 있습니다. 운영 트래픽에서 취약 함수가 호출됐다는 신호가 있으면 우선순위는 빠르게 올라갑니다. 반대로 30일간 관측되지 않았다면 “현재 관측 범위에서는 사용 흔적이 없다”는 유용한 정보가 됩니다.
하지만 부정 증거에는 한계가 있습니다. 낮은 빈도의 admin path, 월말 정산, 장애 복구, 특정 tenant 전용 기능, time-based job은 관찰 기간에 실행되지 않을 수 있습니다. sampling, 언어 runtime의 inlining, native extension, 암호화된 payload, collector 장애도 관측 공백을 만듭니다. 그래서 runtime signal만으로 not affected를 자동 생성하면 안 됩니다.
좋은 evidence record는 신호의 신뢰 범위를 같이 적습니다.
reachability_assessment:
finding: CVE-20XX-YYYY
artifact_digest: sha256:example
workload: invoice-api
environment: production
static_path: "framework adapter -> parser entrypoint"
runtime_observation: "not observed"
observation_window: "2026-09-15..2026-10-15"
coverage: "HTTP ingress 92%, scheduled jobs excluded"
exposure: "authenticated file upload"
decision: "patch in next 7 days; public route control verified"
recheck_trigger: ["dependency update", "feature flag enable", "new upload route"]
expires_at: "2026-11-15"
이 레코드의 핵심은 “미관측” 자체가 아니라 coverage와 제외 경로입니다. runtime data가 부족하면 위험이 낮다는 결론이 아니라 unknown 상태로 두고, 정적 확인·코드 owner 검토·staging 재현으로 보완해야 합니다.
3) reachability는 패치 회피가 아니라 더 빠른 대응 순서를 위한 장치다
도달성 분석을 도입하면 “실행되지 않는 라이브러리는 안 고쳐도 된다”로 오해하기 쉽습니다. 그러나 upstream이 이미 악용 사실을 알렸거나, internet-facing 서비스에 RCE·authentication bypass처럼 파급이 큰 문제가 있거나, 지원 종료된 runtime이라면 runtime evidence를 기다릴 이유가 없습니다. 보호 조치, owner assignment, patch 또는 disable 계획을 먼저 시작해야 합니다.
반대로 대량의 medium finding을 모두 같은 SLA로 처리하면 실제 P0가 review queue에 묻힙니다. 우선순위는 다음 순서로 좁히는 편이 실무적입니다.
- 위협 신호: known-exploited, active advisory, 공급업체의 즉시 조치 권고가 있는가?
- 노출: public ingress, customer data, privileged workload, production control plane에 닿는가?
- 도달성: static path 또는 runtime hit가 확인됐는가? 미확인이라면 관측 coverage는 충분한가?
- 완화와 회복성: 인증, sandbox, network deny, feature disable이 독립적으로 검증됐는가? rollback 가능한가?
- 패치 실행성: compatible fix, test 범위, 배포 window, 대체 통제가 준비됐는가?
이 순서는 CVSS를 버리자는 뜻이 아닙니다. CVSS는 취약점의 잠재적 특성을 보여 주지만, 조직의 실제 attack surface와 patch 순서를 대신 결정하지는 못합니다. 더 중요한 것은 high severity를 닫는 속도를 낮추지 않으면서, 판단 근거가 없는 예외를 없애는 것입니다.
실무 적용
1) 네 단계 판단 파이프라인을 만든다
별도 보안 플랫폼을 먼저 만들 필요는 없습니다. CI와 deploy metadata에서 이미 가진 정보를 아래 네 단계로 연결해도 시작할 수 있습니다.
| 단계 | 최소 산출물 | 기본 결정 |
|---|---|---|
| 1. Inventory | artifact digest ↔ SBOM ↔ workload ↔ owner | 어디에 있는지 모르면 unknown으로 유지 |
| 2. Triage | advisory, severity, exploitation signal, exposure | critical·exploited는 즉시 owner와 보호 조치 |
| 3. Evidence | static use, runtime hit/coverage, control test | reachable·unreachable·unknown을 근거와 함께 기록 |
| 4. Decision | patch, disable, mitigate, accept-temporarily | owner·SLA·만료·재검토 trigger 없으면 완료 아님 |
첫 2주에는 production service 5개와 internet-facing dependency 10개만 골라 inventory 연결률을 봅니다. 그다음 30일 observation window를 두고, traffic coverage와 scheduled job coverage를 따로 기록합니다. 30일은 안전 증명이 아니라 출발점입니다. 월별 업무나 disaster recovery path까지 확인하려면 더 긴 기간과 의도적인 test가 필요합니다.
권장 초기 SLA는 위험과 증거 품질을 함께 봅니다.
- P0: known-exploited 또는 public high-impact path. 24시간 안에 owner 지정·노출 축소·patch/disable 계획, 72시간 안에 검증된 조치.
- P1: reachable이 확인됐거나 privileged production path. 7일 안에 patch 또는 독립적인 완화 통제와 만료일.
- P2: 도달성 미확인 또는 내부 한정. 14일 안에 static/runtime evidence 보강, 30일 안에 patch 여부 결정.
- P3: 현재 evidence상 도달 불가이지만 관측 공백이 있는 항목. 분기별 재검토가 아니라 dependency·route·feature flag 변경 시 즉시 재평가.
숫자는 팀의 서비스 등급과 patch 난이도에 맞춰 바꾸되, unknown을 무기한 backlog로 두지 않는 것이 중요합니다.
2) 예외 문서는 VEX 형식보다 증거 수명을 먼저 관리한다
VEX 같은 machine-readable statement는 자동화에 유용하지만, 포맷을 채웠다고 판단 품질이 생기지는 않습니다. “not affected” 또는 “mitigated”에는 적어도 대상 artifact digest, 환경, 영향받지 않는 이유, 검사 방법, 책임자, 만료일이 있어야 합니다. version range만 적고 실제 배포 image를 적지 않으면, 다음 빌드가 다른 package를 가져왔을 때도 오래된 예외가 붙을 수 있습니다.
특히 아래 변화는 자동 또는 반자동 재검토 trigger로 두세요.
- dependency·base image·compiler 또는 runtime 버전 변경
- public route, upload parser, plugin, feature flag 활성화
- network policy·WAF·authentication flow 변경
- runtime coverage 저하, collector 오류, 새로운 region·tenant rollout
- upstream advisory의 exploitation·fix guidance 변경
예외의 기본 TTL은 low-risk라도 30~90일 안에서 시작하는 편이 좋습니다. 만료 시 “자동 승인 연장” 대신 inventory·runtime coverage·완화 control test를 다시 확인합니다. 이 방식은 policy exception ledger처럼 예외를 편의 메모가 아니라 추적 가능한 운영 부채로 다루는 원리와 같습니다.
3) telemetry의 목적을 보안 판단으로 제한한다
runtime reachability에 필요한 것은 고객 요청 원문이나 전체 stack trace가 아닙니다. package version, component ID, normalized route class, function/module category, decision, sampling rate, collector health, observation window면 많은 판단을 할 수 있습니다. raw URL query, token, 파일명, customer ID 같은 high-cardinality·민감 값을 그대로 label에 넣으면 보안 도구가 새로운 데이터 유출 경로가 됩니다.
측정 지표도 건수보다 품질을 보세요.
artifact_to_owner_coverage: 실행 중인 artifact 중 owner와 SBOM digest가 연결된 비율finding_disposition_sla: P0~P3별 first decision까지 걸린 시간evidence_freshness: 만료 전 evidence record 비율과 오래된 exception 수runtime_coverage_gap: ingress·batch·admin·scheduled path 중 관측되지 않은 비율patch_or_protection_coverage: high-risk finding 중 patch, disable, 독립 control test가 완료된 비율
단, telemetry coverage가 100%에 가깝다는 수치만으로 취약점이 사라진 것은 아닙니다. coverage는 판단의 신뢰도를 알려 주는 메타 지표이고, exploitability와 patch 필요성은 여전히 별도로 결정해야 합니다.
트레이드오프/주의점
첫째, reachability 분석은 false negative를 만들 수 있습니다. reflection, plugin, native library, rare code path, disabled instrumentation은 정적·동적 분석 모두에서 사각지대가 됩니다. 그래서 “도달 불가”는 항상 evidence source와 환경 범위를 가진 조건부 판단이어야 하며, high-impact advisory의 기본 대응을 늦추는 근거가 되어서는 안 됩니다.
둘째, 분석 시스템 자체가 복잡해질 수 있습니다. SBOM format, source mapping, deploy digest, runtime trace, ticket system을 완벽히 통합하려다 도입이 멈추기 쉽습니다. 먼저 public service와 high-value data path처럼 공격면이 큰 영역에서 artifact-to-owner 연결과 만료 예외만 정착시키고, 도달성 분석은 점진적으로 넓히세요.
셋째, 완화 통제를 과신하지 마세요. WAF rule, feature flag off, private network, sandbox는 위험을 낮출 수 있지만 설정 drift, 우회 경로, 운영자 수동 변경에 취약할 수 있습니다. “mitigated” 판정은 control이 존재한다는 선언이 아니라 실제 차단 테스트와 owner 확인까지 통과했을 때만 사용해야 합니다.
마지막으로 이 방식은 patch를 대체하지 않습니다. vendor-supported fix가 있고 회귀 검증이 가능한데도 단지 현재 호출이 드물다는 이유로 패치를 미루면, 다음 기능 릴리스가 오래된 예외를 실제 사고로 바꿀 수 있습니다. 의사결정 우선순위는 active exploitation·외부 노출 차단 > 안전한 patch 적용 > 독립 완화 검증 > 도달성 증거 보강 > 예외 문서화가 적절합니다.
체크리스트 또는 연습
운영 체크리스트
- production artifact digest가 SBOM, workload, environment, owner와 연결된다.
- known-exploited 또는 public high-impact finding은 reachability 분석 전에도 owner·보호 조치·SLA가 지정된다.
- reachability 상태가 reachable, evidence상 unreachable, unknown, coverage gap처럼 불확실성을 표시한다.
- runtime evidence에 관측 기간, sampling·collector 상태, 포함·제외된 ingress/batch/admin 경로가 기록된다.
-
mitigated또는not affected에는 control test, owner, 만료일, 재평가 trigger가 있다. - dependency·route·feature flag·network policy 변경이 관련 exception을 다시 열도록 연결된다.
- telemetry가 요청 원문·credential·개인정보 대신 최소한의 component·coverage metadata를 수집한다.
연습: finding 하나를 증거 기반으로 다시 분류하기
현재 서비스의 medium 또는 high finding 하나를 고르세요. 먼저 실제 production image digest와 SBOM에서 package가 존재하는지 확인합니다. 다음으로 public ingress, admin, batch, background worker 중 어느 경로가 해당 library를 호출하는지 정적 검색과 30일 runtime signal로 나눠 기록합니다. 관측되지 않은 경로가 있다면 unreachable 대신 unknown으로 남기고, code owner에게 필요한 재현 test를 요청합니다. 마지막으로 patch, feature disable, network 제한 중 하나를 선택하되, 그 선택이 유효한지 다시 확인할 날짜와 변경 trigger를 적어 보세요. 이렇게 하면 취약점 티켓은 숫자 목록이 아니라 다음 행동을 결정하는 증거 묶음이 됩니다.
💬 댓글