들어가며
공급망 공격 시리즈에서 cooldown은 “갓 게시된 악성 버전”을 막는 시간 기반 게이트라고 다뤘습니다. 그러나 다음 두 가지는 cooldown 영역 밖입니다.
- 이미 의존 트리에 들어와 있는 패키지에서 새로 발견된 CVE — 게시 후 한참 지나 정상으로 인정받은 버전에서 뒤늦게 발견되는 취약점
- 우리 코드 자체의 취약점 — XSS, 프로토타입 오염, 인젝션 같은 own-code 결함
이 두 가지를 막는 데에 가장 효과적인 두 스캐너 — yarn npm audit과 GitHub CodeQL — 를 다룹니다.
어떤 위험이 있는가
위험 1. 이미 들어와 있는 의존성의 새 CVE
cooldown은 신규 게시 단계에서만 작동합니다. 그런데 보안 취약점은 게시 후 수개월·수년이 지난 뒤 발견되는 경우가 더 흔합니다. 다음 사례들이 대표적입니다.
- Log4Shell (2021, CVE-2021-44228): 8년간 정상으로 알려졌던 Log4j에서 critical RCE 발견
- lodash prototype pollution (CVE-2019-10744): 수년간 안정적으로 사용된 lodash에서 prototype pollution 발견
- xmldom 등 수많은 XML 파서 취약점: 오래 사용된 라이브러리에서 주기적으로 발견되는 XXE/RCE
이 종류의 위험은 “우리가 지금 쓰고 있는 의존성에 알려진 CVE가 있는가?”라는 질문에 답해야 막을 수 있습니다.
위험 2. 우리 코드 자체의 취약점
공급망 방어가 잘 되어 있어도, 우리가 작성한 코드에 다음과 같은 결함이 있다면 그 자체가 공격 경로가 됩니다.
- DOM 조작 시
innerHTML로 사용자 입력을 그대로 삽입 → XSS - 객체 병합 시
__proto__키 검증 누락 → prototype pollution - 정규식에서 catastrophic backtracking → ReDoS
- 동적
import()경로에 사용자 입력 → import injection
이런 결함은 의존성 cooldown으로는 절대 막을 수 없습니다. 자체 코드를 정적 분석해야 잡힙니다.
yarn npm audit: 의존성의 알려진 CVE 탐지
yarn npm audit은 lockfile의 의존성을 GitHub Advisory Database와 매칭해서 알려진 CVE를 찾아 줍니다. PR 단계에서 게이트로 추가하면, 새 CVE가 트리에 추가될 때마다 PR이 실패합니다.
CI 워크플로우에 추가
# .github/workflows/check_audit.yml
name: Dependency Audit
on:
pull_request:
schedule:
- cron: '0 0 * * *' # 매일 1회 점검
permissions:
contents: read
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<SHA> # v6
- uses: actions/setup-node@<SHA> # v6
- run: corepack enable
- run: yarn install --immutable
- run: yarn npm audit --severity high --recursive
옵션 의미:
| 옵션 | 설명 |
|---|---|
--severity high | high 이상 심각도만 실패로 처리 |
--recursive | 모노레포 전체 워크스페이스 검사 |
효과
- 새 CVE가 등록되면 다음 PR이나 다음날 cron에서 즉시 실패
- “이 CVE가 우리에게 영향있는가?”라는 질문에 매일 자동으로 답이 나옴
- false positive가 많으면
--severity critical로 한 단계 더 좁힐 수 있음
CodeQL: 우리 코드의 취약점 탐지
GitHub CodeQL은 public 리포지토리에 무료이며, private 리포지토리에서도 GitHub Code Scanning 기능으로 사용 가능합니다 (GitHub Advanced Security 라이선스).
CodeQL은 코드를 데이터베이스로 변환한 뒤, 보안 쿼리(미리 정의된 수백 개의 규칙)를 SQL처럼 실행해 취약점을 찾습니다. JavaScript/TypeScript의 경우 다음 종류의 결함을 매우 잘 잡습니다.
- XSS (반영형, 저장형, DOM 기반)
- Prototype pollution
- ReDoS (정규식 거부 서비스)
- 안전하지 않은 deserialization
- 인젝션 (SQL, command, path traversal 등)
CI 워크플로우에 추가
# .github/workflows/codeql.yml
name: CodeQL
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 0 * * 1' # 매주 월요일 전체 스캔
permissions:
contents: read
security-events: write
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<SHA> # v6
- uses: github/codeql-action/init@<SHA>
with:
languages: javascript-typescript
- uses: github/codeql-action/analyze@<SHA>
분석 결과는 GitHub Security 탭의 “Code scanning alerts”에 표시되며, PR에도 자동으로 인라인 댓글이 달립니다.
실제 사례
GitHub Security Lab은 Community CodeQL Bounty Program 을 운영하며 — 커뮤니티가 작성한 CodeQL 쿼리들이 — 실제 오픈소스 프로젝트들에서 다수의 CVE를 발견한 사례를 공식 블로그에서 정리하고 있습니다. JavaScript/TypeScript 영역에서는 prototype pollution, ReDoS, XSS, 안전하지 않은 deserialization 같은 패턴 클래스에 대해 사전 정의된 보안 쿼리가 일상적으로 새로운 결함을 잡아내고 있습니다.
자세한 발견 사례 모음은 GitHub Security Lab의 CodeQL Wall of Fame 에서 확인할 수 있습니다.
두 스캐너의 역할 분담
| 도구 | 무엇을 보는가 | 무엇을 막는가 |
|---|---|---|
yarn npm audit | lockfile의 의존성 | 알려진 CVE — 데이터베이스에 등록된 취약점 |
| CodeQL | 자체 소스코드 | 알려지지 않은 own-code 결함 — XSS·인젝션·프로토타입 오염 |
| (참고) cooldown | 새로 게시되는 버전 | 신규 악성 게시 — 막 npm에 올라온 백도어 |
| (참고) Semgrep | 자체 소스코드 (보완) | 코드 스타일·시큐어 패턴 규칙 |
세 가지가 모두 다른 위협을 막습니다. 어느 하나로 다른 둘을 대체할 수 없습니다.
한계
yarn npm audit의 false positive: 의존성 트리에 있더라도 실제 사용 경로에서는 호출되지 않는 코드인 경우가 많습니다. 그런데도 PR을 실패시키면 노이즈가 됩니다.--severity임계값을 조정하거나, 실제 영향 분석은 사람이 판단해야 합니다.- CodeQL의 분석 시간: 큰 모노레포에서는 CodeQL 분석에 수십 분이 걸릴 수 있습니다. PR마다 돌리기 부담스러우면 push와 주간 cron에만 적용하는 절충이 좋습니다.
- 새로 발견되지 않은 CVE: 둘 다 “이미 알려진” 결함을 잡는 도구입니다. 0-day는 별도 영역입니다.
마무리
cooldown이 신규 게시를 거른다면, yarn npm audit과 CodeQL은 이미 들어와 있거나 우리가 직접 만든 위험을 잡습니다. 셋이 함께 운영되어야 공급망 보안이 비로소 다층 구조가 됩니다.
- 우선 도입한다면
yarn npm audit을 PR 게이트에 추가하는 것이 가장 빠릅니다. 설정 한 번이면 끝 - CodeQL은 시간이 들지만 own-code 취약점 발견에 매우 효과적입니다. 주간 cron부터 시작해서 점차 PR 게이트로 옮기는 점진적 도입을 권장합니다.
참고 자료
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku가 개발한 앱을 한번 사용해보세요.Deku가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.