보안 스캔에서 발견된 취약점의 상태를 openclosed로만 나누면 운영 현실을 놓치기 쉽습니다. 코드 수정은 시간이 걸리지만, WAF 규칙·network policy·권한 축소·기능 차단으로 공격 경로를 먼저 줄여야 하는 순간이 있습니다. 이때 “취약점이 사라졌다"고 기록하면 위험합니다. 코드는 여전히 취약하지만, 별도 통제가 현재 exploit 가능성을 낮추는 상태이기 때문입니다.

GitHub는 2026년 8월 20일 Code Scanning alert에 Mitigated dismissal reason을 추가했습니다. 외부 통제로 위험을 줄인 항목을 Won't fix와 구분하고, 정식 예외·위험 수용 절차에 연결하기 위한 변화입니다. 이어 8월 18일에는 credential 유형별 revoke·deauthorize 기능을 추가해 incident 때 PAT, SSH key, OAuth token처럼 필요한 자격증명 종류만 좁혀 회수할 수 있게 했습니다. 두 변화의 공통점은 탐지 결과를 단순 목록이 아니라 통제 범위와 회수 경로가 있는 실행 상태로 다룬다는 데 있습니다.

이 글은 Security Triage Context Plane, Security Default Setup Rollout, Tamper-Evident Audit Log의 다음 단계입니다. 앞선 글이 탐지·중앙 rollout·감사 증거를 다뤘다면, 여기서는 “지금 고칠 수 없는 취약점"을 어떻게 거짓 종결 없이 관리할지에 집중합니다.

참고한 공식 신호:

이 글에서 얻는 것

  • fixed, mitigated, accepted risk, false positive, won't fix를 같은 말로 취급하지 않는 기준을 얻습니다.
  • WAF·egress policy·권한 회수·feature flag 같은 보완 통제를 취약점 레코드에 연결하는 방법을 배웁니다.
  • 예외에 필요한 증거, 만료일, 재검증, 재오픈 조건을 숫자와 역할로 설계할 수 있습니다.
  • “열린 취약점 수를 줄이는 것"과 “실제 노출 위험을 낮추는 것"을 분리해 대시보드를 읽는 법을 익힙니다.

핵심 개념/이슈

1) Mitigated는 해결 상태가 아니라 제한된 위험 상태다

다섯 상태를 구분하면 판단이 훨씬 선명해집니다.

상태코드에 취약점이 남았는가현재 공격 경로다음 행동
Fixed아니오수정·배포로 제거regression test와 배포 범위 확인
Mitigated보완 통제로 제한통제 증거·만료·영구 수정 추적
Accepted risk조직이 명시적으로 수용승인 근거·review cadence·범위 제한
False positive해당 없음탐지 자체가 틀림rule·analysis 근거 보존
Won't fix남아 있을 수 있음사유를 더 구체적 상태로 재분류

예를 들어 SQL injection 가능성이 있는 오래된 admin endpoint에 WAF virtual patch를 적용했다고 해 봅시다. 외부 인터넷에서 차단되더라도, 내부 네트워크·allowlist 파트너·우회 encoding·새 routing 경로가 같은 rule을 통과할 수 있습니다. 이는 fixed가 아니라 mitigated입니다. 반대로 endpoint를 완전히 제거하고 배포·로그·synthetic probe로 404를 확인했다면 fixed에 가까워집니다.

Won't fix는 특히 위험한 묶음입니다. 실제 오탐, 제품 종료 예정, 위험 수용, 외부 통제 적용, 수정 비용 과다 같은 전혀 다른 이유가 한 label에 섞이기 때문입니다. GitHub의 새 상태는 이 중 통제로 줄인 위험을 분리할 수 있게 한 신호입니다. 분류가 정확해야 보안 triage도 제대로 우선순위를 정할 수 있습니다.

2) 보완 통제는 취약점의 “주석"이 아니라 실행 중인 의존성이다

Mitigated alert 하나는 다른 운영 자산에 의존합니다. WAF rule, gateway route, network policy, identity policy, feature flag, credential revocation 중 하나가 바뀌면 완화가 사라질 수 있습니다. 그러므로 스캐너 화면에 “WAF 적용"이라고 적는 것만으로는 부족합니다.

최소한 아래 레코드를 연결하세요.

vulnerability_exception:
  id: VULN-2026-041
  finding: "codeql/sql-injection in admin-export"
  status: mitigated
  affected_scope:
    repos: ["admin-api"]
    routes: ["POST /internal/export"]
    environments: ["prod"]
  compensating_control:
    type: waf_rule
    control_id: "waf-8931"
    enforcement: block
    test_evidence: "synthetic-2026-08-26-17"
  owner: platform-security
  expires_at: "2026-09-25"
  permanent_fix: "SEC-1882"
  reopen_if:
    - control_disabled
    - route_or_parameter_shape_changed
    - bypass_test_passes

여기서 핵심은 control ID와 재오픈 조건입니다. WAF rule이 삭제되거나, API path가 바뀌거나, edge bypass가 생겼을 때 예외는 자동으로 의심 상태가 되어야 합니다. 권한 정책 shadow rollout처럼 통제도 적용 전후의 실제 요청 분포와 false positive를 봐야 합니다. 정책 이름이 존재한다는 사실만으로 보호 효과가 증명되지는 않습니다.

3) 완화의 강도는 exploit 경로와 통제 위치가 얼마나 가까운지로 판단한다

모든 보완 통제의 질이 같지는 않습니다. 취약 코드 바로 앞에서 입력을 구조적으로 제한하는 것이, 먼 네트워크 경계에서 특정 IP를 막는 것보다 대체로 강합니다. 아래 순서는 일반적인 출발점이며, 실제 위협 모델에 따라 조정해야 합니다.

통제강점자주 놓치는 약점증거
코드 수정·안전한 API취약 원인 자체 제거회귀·미배포 환경unit/integration test, release evidence
입력 스키마·권한 검사호출 지점과 가까움다른 entrypoint 누락contract test, denied audit
WAF/edge rule빠른 virtual patch내부·우회 경로, rule driftblock log, bypass test
network policy도달 범위 축소내부 lateral movementflow log, deny test
credential revoke탈취 자격증명 무력화다른 token type·새 발급audit event, re-auth test
모니터링만 강화탐지 속도 향상공격 자체는 막지 못함alert-to-action drill

따라서 위험한 SQL query가 public path에서만 발생하고, 모든 public ingress가 한 WAF를 반드시 거친다는 증거가 있을 때 WAF 완화가 의미를 가질 수 있습니다. 같은 코드가 batch, VPN, partner route에서도 호출되면 scope는 좁지 않습니다. 이 경우 미완화 또는 부분 완화로 기록하고 수정 우선순위를 올리는 편이 정직합니다.

4) 자격증명 회수도 “전부 끊기"보다 blast radius에 맞춰야 한다

GitHub의 token-type-specific revocation은 incident response가 무조건 전체 자격증명을 끊는 방식에서 더 세밀한 회수로 이동한다는 사례입니다. 예를 들어 노출된 PAT만 회수할 수 있다면 SSH key까지 함께 끊어 개발자의 복구를 늦추지 않을 수 있습니다. 그러나 세밀한 회수는 반대로 영향 없는 token type이 정말 안전한가를 확인해야 한다는 책임을 만듭니다.

회수 우선순위는 다음처럼 잡을 수 있습니다.

  1. 노출 증거나 비정상 사용이 있는 credential type을 먼저 revoke한다.
  2. 같은 owner·scope·발급 방식의 인접 credential을 inventory로 확인한다.
  3. audit log에서 회수 완료, 재인증, 실패한 자동화 job을 확인한다.
  4. 장기 토큰을 다시 발급하기 전에 scope 축소·수명 단축·workload identity 전환 가능성을 검토한다.
  5. incident 종료는 “revoke 버튼 클릭"이 아니라 후속 사용이 거절됐고 정상 업무가 대체 경로로 복구됐을 때 선언한다.

이 흐름은 API Key Lifecycle과 Rotation/Revocation에서 다룬 수명주기와도 맞닿습니다. 회수 기능이 있더라도 owner, scope, 마지막 사용, 재발급 규칙이 없으면 실전에서는 어느 키를 끊을지 판단하기 어렵습니다.

실무 적용

1) Mitigated 예외를 7개 필수 필드로 승인한다

보완 통제가 필요할 때 긴 자유 형식 문서 대신 다음 일곱 필드를 필수로 두면 누락을 줄일 수 있습니다.

  1. Finding과 영향 경로: rule ID, repository, route·function, 영향 환경, 데이터 민감도
  2. 왜 지금 고치지 못하는가: release freeze, vendor patch 대기, 레거시 호환성 등 구체적 이유
  3. 보완 통제: control type, ID, 정책 버전, 적용 범위, default deny 여부
  4. 효과 검증: 정상 요청·공격 형태·우회 시도의 결과와 실행 시각
  5. Owner와 승인자: 서비스 owner와 security owner를 분리
  6. 만료일과 영구 수정 ticket: High/Critical은 기본 30일, Medium/Low는 최대 90일에서 재검토
  7. 재오픈 조건: control disable, 경로 변경, bypass test 성공, 새 노출 환경 발견

Critical finding에 만료일 없는 Mitigated를 허용하면 사실상 영구 Won't fix가 됩니다. 반대로 사소한 finding을 매주 재승인하게 하면 운영 피로가 커집니다. 그래서 위험도와 공격 표면을 함께 봅니다. 공개 인터넷·권한 상승·원격 코드 실행은 더 짧게, 내부 read-only·정확한 network isolation이 있는 항목은 더 길게 검토할 수 있습니다.

2) 두 단계로 통제를 검증한다: 배포 직후와 변경 감시

첫 번째 검증은 통제 배포 직후입니다. WAF라면 차단 대상 payload가 403/406으로 거부되는지, network policy라면 허용되지 않은 namespace에서 연결이 실패하는지, credential revoke라면 기존 token이 더 이상 API를 호출하지 못하는지 확인합니다. 이때 운영 데이터나 실제 공격 payload를 그대로 쓰지 말고, 안전한 시험 계정·synthetic probe·마스킹된 fixture를 사용합니다.

두 번째 검증은 통제가 계속 존재하는지 보는 일입니다. route·ingress·feature flag·WAF rule·role binding이 바뀌면 이전 증거는 약해집니다. 다음 조건 중 하나가 발생하면 해당 mitigated exception을 다시 검토 대상으로 올립니다.

  • control ID가 변경·삭제되었거나 enforcement가 block에서 monitor로 낮아짐
  • 취약 함수의 파일·파라미터·호출 entrypoint가 바뀜
  • 새 환경, 새 region, 새 ingress가 추가됨
  • 30일 동안 차단 로그와 synthetic probe 증거가 한 번도 없음
  • 예외 만료일에 도달했는데 영구 수정 ticket이 진행되지 않음

감사 로그 설계에 exception ID와 control ID를 남기면, 통제가 바뀐 날 어떤 취약점의 보호 가정이 깨졌는지 역추적할 수 있습니다.

3) 대시보드는 “닫힌 수” 대신 위험의 흐름을 보여준다

Mitigated 상태가 생기면 open finding 수는 줄어 보일 수 있습니다. 하지만 실제 위험이 줄었는지는 다른 지표를 봐야 합니다.

지표건강한 신호위험 신호
만료된 mitigated 예외0건1건이라도 High/Critical이면 즉시 review
예외의 평균 나이위험 등급 목표 안90일 이상 누적 증가
통제 검증 성공률synthetic probe 100%누락·실패 또는 evidence 없음
영구 수정 전환율분기별 상승예외만 계속 연장
control drift 후 재검토변경 1영업일 안owner 없는 장기 미확인
우회/재노출0건block→monitor 변경, bypass 성공

작은 팀이라면 처음부터 완벽한 플랫폼을 만들 필요가 없습니다. Mitigated High/Critical 항목만 YAML이나 issue template에 모으고, 주 1회 20분 review로 만료일·ticket·control 증거만 확인해도 큰 차이가 납니다. 중요한 것은 alert를 닫는 속도가 아니라, 보호 가정이 유효한지 다시 확인하는 반복입니다.

4) 현실적인 30일 도입 순서

1주차 — 현재 dismissal 정리. 최근 90일 code scanning dismissal을 false positive, fixed, accepted risk, mitigated, unknown으로 다시 분류합니다. 사유가 없는 won't fix부터 owner를 지정합니다.

2주차 — High/Critical 한정 템플릿 적용. 새 mitigated exception에 7개 필드와 30일 만료를 요구합니다. 기존 항목에는 일괄 차단 대신 evidence 수집 태그를 먼저 붙입니다.

3주차 — 통제와 change event 연결. WAF·network policy·credential revoke·feature flag의 control ID를 exception record에 넣고, 변경 이벤트가 발생하면 관련 exception을 검색할 수 있게 합니다.

4주차 — 재검토 자동화와 수정 우선순위화. 만료 7일 전 알림, control drift 시 재오픈 후보, 2회 이상 연장된 항목의 security review를 시작합니다. 수정 ticket이 없는 exception은 연장하지 않는 것을 기본값으로 둡니다.

이 순서의 우선순위는 현재 exploit 차단 > 통제 효과 증명 > 책임과 만료 > 영구 수정 일정 > 대시보드 미관입니다. open finding 수를 빨리 낮추려고 상태만 바꾸면 우선순위가 거꾸로 됩니다.

트레이드오프/주의점

  1. 보완 통제는 patch보다 빠르지만 원인을 제거하지 않습니다. WAF는 특히 긴급 대응에 유용하지만, parsing 차이·새 endpoint·내부 경로를 놓칠 수 있습니다. 가능한 한 수정 배포로 돌아갈 ticket을 같이 만드세요.
  2. 너무 짧은 만료일은 형식적인 재승인을 만들 수 있습니다. 위험 등급과 변경 빈도에 맞춰 30/60/90일처럼 차등을 두되, 만료 없는 예외는 피합니다.
  3. policy가 있다는 것과 enforcement가 된다는 것은 다릅니다. monitor mode, rule ordering, 잘못된 selector, stale inventory는 통제를 무력화합니다. 반드시 deny·block 결과를 시험합니다.
  4. 세밀한 credential revoke는 피해를 줄이지만 조사 범위를 줄이지 않습니다. PAT 하나만 노출됐다는 가설이 틀릴 수 있으므로 같은 principal의 토큰·SSH key·OAuth authorization·CI secret를 inventory에서 함께 확인해야 합니다.
  5. 대시보드 순위가 팀의 보안 우선순위를 왜곡할 수 있습니다. open count를 줄이는 것이 평가 지표가 되면 사람은 “Mitigated"를 남용합니다. 만료 초과·통제 drift·영구 수정 전환율을 같이 평가해야 합니다.

체크리스트 또는 연습

체크리스트

  • fixed, mitigated, accepted risk, false positive, won't fix의 의미와 승인 기준을 문서화했다.
  • Mitigated 항목에 finding, scope, control ID, evidence, owner, 만료, 영구 수정 ticket이 있다.
  • 보완 통제가 실제 block/deny하는지 배포 직후 synthetic test로 확인했다.
  • control 변경·경로 변경·새 환경·만료가 예외 재검토 또는 재오픈 조건으로 연결된다.
  • High/Critical 예외의 기본 재검토 주기가 30일 이하이고, 만료 예외를 주간으로 검토한다.
  • credential 회수는 token type, owner, scope, audit log, 업무 복구 확인까지 포함한다.
  • 보안 대시보드에 예외 수뿐 아니라 evidence freshness, control drift, 영구 수정 전환율이 있다.

연습

  1. 현재 보안 finding 하나를 골라 Fixed, Mitigated, Accepted risk 중 어느 상태가 정직한지 판단해 보세요. 공격 경로와 통제 증거를 두 줄씩 적습니다.
  2. WAF rule 하나를 보완 통제로 등록한다고 가정하고 rule ID, 적용 route, 정상·공격·우회 probe, 만료일, 재오픈 조건을 YAML로 작성해 보세요.
  3. 최근 90일의 won't fix 10개를 표본으로 골라 이유가 false positive인지, 외부 통제인지, 위험 수용인지 분류해 보세요. 이유가 없는 항목에는 owner와 재검토 날짜를 붙입니다.
  4. PAT 유출 가상 incident에서 PAT만 revoke하는 조건과 SSH key·OAuth token까지 넓혀야 하는 조건을 각각 3개씩 정리해 보세요.

관련 글