1. 취약 패키지가 설치됐다는 사실과 취약 코드가 실행된다는 사실은 다르다
프로젝트의 잠금 파일에 보안 취약점이 알려진 패키지 버전이 있으면 의존성 경고가 생깁니다. 이 경고는 중요한 출발점이지만 애플리케이션이 그 패키지의 취약한 함수까지 실제로 호출한다는 뜻은 아닙니다. 같은 라이브러리에서도 사용하는 기능이 다르고, 전이 의존성으로만 포함됐지만 실행 경로에 나타나지 않는 경우도 있습니다.
GitHub는 2026년 10월 28일 Dependabot 경고에 도달 가능성 분석을 추가하는 공개 미리보기를 발표했습니다. 현재 JavaScript와 TypeScript 저장소에서 npm, Yarn 또는 pnpm 잠금 파일이 있을 때, CodeQL이 저장소와 의존성의 호출 그래프를 만들고 GitHub가 선별한 취약 함수 정보까지 이어지는 호출 경로를 찾습니다.
이 기능의 목적은 경고를 없애는 것이 아니라 먼저 고칠 경고를 정하는 데 문맥을 더하는 것입니다. 도달 가능한 취약점은 우선 조사하고, 도달하지 않는 것으로 분석된 경고도 자동으로 닫지 않습니다. 코드가 바뀌면 경로가 새로 생길 수 있고, 정적 분석이 모든 동적 동작을 완전하게 볼 수 없기 때문입니다.
근거 자료 · GitHub Changelog · Prioritize Dependabot alerts with reachability analysis · GitHub Docs · About reachability analysis for Dependabot alerts
2. 호출 그래프는 함수 사이의 길을 지도처럼 표현한다
호출 그래프에서 노드는 함수나 메서드이고, 간선은 한 함수가 다른 함수를 호출할 수 있다는 관계입니다. 애플리케이션의 진입 함수에서 출발해 라이브러리 내부의 취약 함수까지 간선을 따라갈 수 있으면 호출 경로가 존재합니다. 예를 들어 `handleUpload → parseFile → library.decode → vulnerableCopy`처럼 저장소 코드와 외부 패키지 코드를 연결할 수 있습니다.
정적 분석은 프로그램을 직접 실행하지 않고 소스와 빌드 정보를 분석합니다. 여러 입력과 실행 상황을 한꺼번에 고려할 수 있지만 JavaScript의 동적 속성 접근, 런타임에 정해지는 모듈, 반사 호출, 생성된 코드처럼 대상이 명확하지 않은 동작에서는 확정이 어렵습니다. 이때 ‘경로 없음’으로 단정하기보다 불확실한 상태를 남기는 편이 안전합니다.
잠금 파일도 중요합니다. package.json의 버전 범위만으로는 실제 설치 버전을 확정하기 어렵지만 잠금 파일은 선택된 버전과 전이 의존성 관계를 보여 줍니다. 호출 그래프는 코드의 함수 관계를, 의존성 그래프는 패키지와 버전 관계를, 보안 권고는 영향을 받는 버전과 취약 함수를 제공합니다. 세 자료가 맞물려야 경고에 코드 문맥을 붙일 수 있습니다.
의존성 잠금 파일: app → package-a@2.1 → package-b@4.3
보안 권고: package-b@4.3의 vulnerableCopy()가 영향 받음
호출 그래프: handleUpload() → package-a.parse()
→ package-b.decode() → vulnerableCopy()
판정 근거: 애플리케이션 코드에서 취약 함수까지 호출 경로 존재3. 네 가지 판정은 확신의 정도와 다음 행동을 구분한다
GitHub 문서는 분석 결과를 Reachable, Potentially reachable, Unreachable, Reachability unavailable 네 가지로 설명합니다. Reachable은 저장소 코드에서 취약 함수까지 하나 이상의 호출 경로를 찾은 경우입니다. Potentially reachable은 호출 가능성을 배제하지 못한 상태이며 도달 가능한 경고와 함께 우선 처리할 것을 권합니다.
Unreachable은 분석이 완료됐지만 호출 경로를 찾지 못한 경우입니다. 낮은 우선순위 신호로 사용할 수 있으나 안전 보증은 아닙니다. Reachability unavailable은 지원하지 않는 생태계, 스캔 실패나 시간 초과 등으로 판정을 제공하지 못한 경우이므로 심각도·EPSS·직접 또는 전이 의존성·운영 환경 같은 다른 신호로 판단합니다.
공식 발표에 따르면 공개 미리보기에서 일부 모노레포와 여러 디렉터리의 매니페스트는 지원되지 않을 수 있고 분석이 3시간을 넘으면 일부 결과가 unavailable로 표시될 수 있습니다. 판정이 없다는 사실을 ‘도달하지 않음’으로 바꾸면 안 됩니다. 데이터 모델에서도 unavailable과 unreachable을 다른 값으로 저장해야 합니다.
| 판정 | 의미 | 우선 행동 | 잘못된 해석 |
|---|---|---|---|
| Reachable | 취약 함수까지 호출 경로 발견 | 경로를 확인하고 수정 우선 | 공격이 반드시 성공함 |
| Potentially reachable | 호출을 배제하지 못함 | Reachable과 함께 우선 검토 | 증거가 없으니 안전함 |
| Unreachable | 완료된 분석에서 경로 미발견 | 우선순위를 낮추되 계속 추적 | 경고를 즉시 닫아도 됨 |
| Unavailable | 분석 불가·실패·시간 초과 | 다른 위험 신호로 분류 | Unreachable과 같은 뜻 |
근거 자료 · GitHub Docs · About reachability analysis for Dependabot alerts
4. 도달 가능성과 공격 가능성은 같은 질문이 아니다
호출 경로가 존재해도 공격자가 그 경로에 필요한 입력을 조작할 수 있는지는 별도 문제입니다. 관리자만 접근하는 내부 기능일 수 있고, 입력 검증이나 네트워크 방화벽이 공격 조건을 막을 수도 있습니다. 반대로 현재 호출 경로가 보이지 않아도 다음 코드 변경에서 취약 함수를 사용하거나 분석이 동적 호출을 놓칠 수 있습니다.
그래서 GitHub 문서는 도달 가능성을 심각도, Exploit Prediction Scoring System인 EPSS, 의존성 범위, 직접·전이 관계, 운영 문맥과 함께 사용할 것을 권합니다. 심각도는 성공했을 때 영향, EPSS는 공개된 취약점이 실제로 악용될 가능성을 추정하는 별도 신호이며, 도달 가능성은 코드가 취약 함수까지 이어지는지를 봅니다.
우선순위 점수 하나로 모든 판단을 감추기보다 각 신호와 근거를 함께 보여 주는 편이 좋습니다. 인터넷에 노출된 서비스의 Reachable 경고와 개발 전용 도구의 Unreachable 경고는 처리 순서가 다를 수 있습니다. 다만 점수가 낮아졌다는 이유로 업데이트 계획에서 영구 제외하지 않고 재검토 날짜를 둡니다.
| 신호 | 답하는 질문 | 한계 |
|---|---|---|
| 심각도 | 악용 성공 시 영향이 얼마나 큰가 | 우리 코드의 사용 여부는 모름 |
| EPSS | 가까운 기간에 악용될 가능성은 어느 정도인가 | 개별 서비스 노출 조건은 모름 |
| 도달 가능성 | 우리 코드에서 취약 함수까지 길이 있는가 | 실제 공격 성공을 증명하지 않음 |
| 운영 문맥 | 인터넷 노출·데이터 민감도·보호 장치는 무엇인가 | 조직이 직접 최신 상태로 관리해야 함 |
근거 자료 · GitHub Docs · Prioritizing Dependabot alerts using metrics
5. Python으로 작은 호출 그래프를 직접 탐색한다
다음은 CodeQL이나 GitHub 서비스를 재현했다는 주장이 아니라 그래프 탐색 원리를 배우는 실습 제안입니다. 함수 이름을 노드로, 호출 관계를 간선으로 가진 가상 JSON을 만들고 애플리케이션 진입점에서 취약 함수까지 너비 우선 탐색을 수행합니다. 경로를 찾으면 부모 노드를 역추적해 호출 순서를 출력합니다.
분석 결과는 reachable과 unreachable 두 값만 만들지 않습니다. 그래프에 동적 호출이나 해석하지 못한 모듈이 있으면 potentially_reachable로, 파서 실패나 시간 제한을 넘기면 unavailable로 기록합니다. 실제 정적 분석보다 매우 단순한 모델이라는 한계를 결과 화면에 명시합니다.
Python의 `ast` 모듈로 작은 Python 파일의 함수 호출을 읽어도 좋지만 외부 라이브러리와 동적 호출까지 정확히 분석한다고 주장해서는 안 됩니다. 학습 목표는 보안 도구를 만드는 것이 아니라 그래프 입력, 탐색 결과, 불확실성과 증거 경로가 어떻게 연결되는지 이해하는 것입니다.
# 교육용 의사코드
def find_path(graph, starts, target):
queue = [(node, [node]) for node in starts]
visited = set()
while queue:
node, path = queue.pop(0)
if node == target:
return {'verdict': 'reachable', 'path': path}
if node in visited:
continue
visited.add(node)
for next_node in graph.get(node, []):
queue.append((next_node, path + [next_node]))
return {'verdict': 'unreachable', 'path': []}6. SQL과 Java로 경고의 시간 변화와 수정 흐름을 관리한다
도달 가능성은 한 번 계산하고 끝나는 속성이 아닙니다. 코드, 잠금 파일, 보안 권고의 취약 함수 정보가 바뀌면 판정도 달라질 수 있습니다. SQL에는 현재 판정만 덮어쓰지 말고 커밋 SHA, 패키지 버전, 권고 ID, 분석 시각, 판정과 경로 해시를 실행 이력으로 저장합니다.
Java API는 경고 목록, 판정 근거, 담당자와 수정 pull request를 연결합니다. 사용자는 Reachable과 Potentially reachable을 먼저 필터링하고 경로를 검토한 뒤 패키지 업데이트, 취약 기능 제거, 임시 완화 중 하나를 선택합니다. 경고를 닫는 권한과 우선순위를 바꾸는 권한도 역할로 나눕니다.
수정 후에는 단위 테스트와 통합 테스트, 잠금 파일 변경, 새로운 도달 가능성 결과를 함께 확인합니다. 패키지 버전만 올랐다고 완료하지 않고 애플리케이션이 정상 작동하는지 확인합니다. 반대로 경로가 사라졌다는 결과만으로 취약 버전을 계속 유지하는 관행도 피합니다.
CREATE TABLE reachability_scan (
scan_id BIGINT PRIMARY KEY, commit_sha VARCHAR(40),
advisory_id VARCHAR(100), package_name VARCHAR(200),
package_version VARCHAR(80), verdict VARCHAR(40),
path_hash VARCHAR(64), analyzed_at TIMESTAMP,
analysis_status VARCHAR(40), error_reason TEXT
);
CREATE TABLE remediation (
advisory_id VARCHAR(100), owner_id VARCHAR(100),
decision VARCHAR(40), pull_request_url TEXT,
due_at TIMESTAMP, reviewed_at TIMESTAMP
);7. AI와 클라우드는 우선순위 설명을 돕되 판정을 꾸며내면 안 된다
AI는 경고 설명, 호출 경로와 변경 파일 요약, 수정 후보 비교를 도울 수 있습니다. 하지만 분석 결과가 unavailable인데 코드 경로를 추측해 reachable이나 unreachable로 바꾸면 안 됩니다. 에이전트 입력에는 판정, 경로 증거, 심각도, EPSS, 운영 문맥의 출처와 분석 시각을 구조화해 제공합니다.
클라우드 파이프라인에서는 잠금 파일이나 소스가 변경될 때 분석을 실행하고, 결과를 보안 대시보드와 알림에 연결할 수 있습니다. 시간 초과를 성공이나 안전으로 처리하지 않고 unavailable로 전송하며, 경고 수 급증·분석 실패율·오래된 판정에 별도 경보를 둡니다. 비공개 소스와 호출 경로가 외부 AI 서비스로 전송되는 범위도 정책으로 제한합니다.
GitHub 공개 미리보기는 관리형 GitHub Actions 워크플로에서 실행되고 자체 호스팅 러너를 지원하지 않으며 기본값이 꺼져 있습니다. 실제 사용 전 지원 언어·패키지 관리자·저장소 유형과 데이터 처리 조건을 확인해야 합니다. 교육 실습은 이 제품 기능 활성화를 요구하지 않으며 가상 그래프로 충분히 원리를 배울 수 있습니다.
- AI 요약이 원래 판정과 호출 경로 증거를 인용하는가
- Unavailable을 안전 또는 Unreachable로 바꾸지 않는가
- 분석 시각과 커밋 SHA를 함께 보여 주는가
- 소스 코드와 보안 데이터의 전송 범위를 통제하는가
- 수정 제안은 테스트와 사람 검토를 거치는가
근거 자료 · GitHub Docs · Configuring reachability analysis for Dependabot alerts
8. 2주 프로젝트는 경고 개수보다 판단 근거를 평가한다
첫 주에는 함수 30개와 외부 패키지 5개로 구성된 가상 호출 그래프를 만들고 Python 탐색기를 구현합니다. 직접 경로, 끊긴 경로, 동적 호출, 파서 실패 네 시나리오를 만들어 네 가지 판정을 출력합니다. 각 결과에는 경로 또는 불확실성 이유가 반드시 포함되게 합니다.
둘째 주에는 결과를 SQL에 누적하고 Java API로 경고 목록과 수정 상태를 제공합니다. 커밋이 바뀌면서 Unreachable이 Reachable로 바뀌는 사례, 취약 패키지를 업데이트해 경고가 해결되는 사례를 시연합니다. AI 요약 기능을 넣는다면 원문 증거가 없는 문장을 자동으로 표시하는 검증 규칙도 추가합니다.
평가는 많이 차단한 팀이 아니라 판정과 한계를 정확히 구분한 팀에 높은 점수를 줍니다. 호출 경로 재현, 시간에 따른 이력, 불확실성 보존, 최소 권한, 수정 테스트를 확인합니다. 이렇게 하면 보안 경고를 무조건 지우는 작업이 아니라 제한된 시간 안에 더 위험한 문제부터 근거 있게 고치는 데이터 기반 개발 과정으로 이해할 수 있습니다.
| 평가 항목 | 확인 질문 | 증거 |
|---|---|---|
| 그래프 정확성 | 진입점부터 취약 함수 경로가 재현되는가 | 노드·간선과 경로 출력 |
| 불확실성 | Potentially reachable과 Unavailable을 보존했는가 | 오류·동적 호출 시나리오 |
| 시간 이력 | 코드 변경 전후 판정을 비교할 수 있는가 | SQL 스캔 기록 |
| 우선순위 | 심각도·EPSS·운영 문맥을 함께 봤는가 | 결정표와 담당자 기록 |
| 수정 검증 | 업데이트 뒤 기능과 경로를 다시 검사했는가 | 테스트와 새 스캔 결과 |
학생이 이 이슈에서 확인할 것
- 의존성 그래프와 함수 호출 그래프의 차이를 설명할 수 있나요?
- 네 가지 도달 가능성 판정과 다음 행동을 구분했나요?
- 도달 가능성과 실제 공격 가능성이 같은 뜻이 아님을 이해했나요?
- 커밋·패키지 버전·분석 시각별 판정 이력을 남겼나요?
- AI 요약이 불확실성을 지우거나 근거 없는 경로를 만들지 않게 했나요?
함수 30개와 외부 패키지 5개의 가상 호출 그래프로 의존성 도달 가능성 분석기를 만드세요. Python 탐색, SQL 판정 이력, Java 경고 API, AI 근거 요약과 클라우드 실행 흐름을 연결하고 네 가지 판정의 한계와 수정 결과를 평가하세요.
관심 기술을 대학의 프로젝트로 연결하세요.
전공의 학습 흐름을 이해하고 학생이 직접 만든 결과를 확인한 뒤, 자신에게 맞는 입학 계획을 세워 보세요.