들어가며 — Red Hat마저 뚫렸다
2026년 6월, Hacker News 1면을 장식한 사건이 하나 있었습니다. Red Hat Cloud Services의 공식 JavaScript 클라이언트 저장소인 RedHatInsights/javascript-clients와 관련된 악성 npm 패키지가 발견된 것입니다. 해당 저장소의 이슈 492번에는 사용자들이 의심스러운 패키지 버전과 비정상적인 install script 동작을 보고하는 글이 올라왔고, GeekNews에서도 빠르게 번역 요약이 공유되며 국내 커뮤니티에서도 큰 화제가 됐습니다.
이 사건이 충격적인 이유는 단순합니다. Red Hat은 오픈소스 생태계에서 가장 보안에 민감한 벤더 중 하나이고, 엔터프라이즈 고객 다수가 그들의 클라이언트 라이브러리를 신뢰 기반으로 설치하기 때문입니다. "유명 벤더의 공식 스코프 패키지니까 안전하겠지"라는 가정이 무너진 순간, 우리 모두의 npm install은 잠재적 공격 벡터가 됩니다.
사실 npm 공급망 공격은 새로운 이야기가 아닙니다. event-stream(2018), ua-parser-js(2021), node-ipc(2022), 그리고 2025년에 연쇄적으로 터진 대규모 토큰 탈취 웜 사태까지, 매년 더 정교해지고 있습니다. 달라진 것은 공격 대상의 급입니다. 개인 메인테이너의 사이드 프로젝트가 아니라, 대형 벤더의 공식 패키지와 빌드 인프라가 직접 표적이 되는 시대가 왔습니다.
이 글에서는 npm 공급망 공격의 유형을 체계적으로 분류하고, 개인 개발자부터 조직 차원까지 적용할 수 있는 방어 스택을 코드와 설정 예제 중심으로 정리합니다.
공급망 공격의 5가지 유형
공격 유형을 먼저 분류해야 방어 수단을 매핑할 수 있습니다. npm 생태계에서 관찰된 공격은 크게 다섯 가지로 나뉩니다.
| 유형 | 공격 방식 | 대표 사례 | 핵심 방어 |
| --- | --- | --- | --- |
| 타이포스쿼팅 | 유사 이름 패키지 등록 | crossenv 대 cross-env | 의존성 리뷰, 스캐너 |
| 계정 탈취 | 메인테이너 npm 계정 침해 | ua-parser-js | 2FA 강제, provenance |
| install script | postinstall에서 악성 코드 실행 | eslint-scope | ignore-scripts |
| 의존성 혼동 | 사내 패키지명을 공개 레지스트리에 선점 | 2021년 Birsan 연구 | 스코프 고정, 레지스트리 설정 |
| 빌드 인프라 침투 | CI나 배포 파이프라인 자체를 침해 | SolarWinds, 2026 Red Hat 사건 | 격리 빌드, 서명 검증 |
각 유형을 조금 더 깊이 들여다보겠습니다.
1. 타이포스쿼팅 (Typosquatting)
가장 고전적인 수법입니다. 인기 패키지와 한두 글자 다른 이름으로 악성 패키지를 등록하고, 오타를 낸 개발자가 설치하기를 기다립니다. 변형으로 콤보스쿼팅이 있는데, react-dom-router처럼 실존하는 패키지들의 이름을 조합해 그럴듯한 이름을 만드는 방식입니다.
2. 계정 탈취 (Account Takeover)
메인테이너의 npm 계정 자격 증명을 피싱이나 크리덴셜 스터핑으로 확보한 뒤, 정상 패키지의 새 버전에 악성 코드를 심어 배포합니다. 패키지 이름은 진짜이므로 타이포스쿼팅보다 훨씬 위험합니다. 2021년 ua-parser-js 사건에서는 주간 다운로드 수백만 건의 패키지에 암호화폐 채굴기와 정보 탈취 코드가 들어갔습니다.
3. install script 악용
npm은 패키지 설치 시 preinstall, install, postinstall 스크립트를 자동 실행합니다. 코드를 한 줄도 import하지 않아도, 설치하는 순간 임의 코드가 실행된다는 뜻입니다. 2025년 대규모 웜 사태에서 악성 코드가 정확히 이 지점을 노렸습니다. 개발자 머신의 환경 변수, npm 토큰, 클라우드 자격 증명을 수집해 외부로 전송하고, 탈취한 npm 토큰으로 또 다른 패키지를 감염시키는 자기 복제 구조였습니다.
4. 의존성 혼동 (Dependency Confusion)
사내 전용 패키지 이름이 공개 레지스트리에 등록되어 있지 않으면, 공격자가 같은 이름으로 더 높은 버전을 공개 레지스트리에 올립니다. 레지스트리 우선순위 설정이 잘못된 빌드 환경은 사내 패키지 대신 공개된 악성 패키지를 받아옵니다. 2021년 Alex Birsan이 이 기법으로 Apple, Microsoft 등 35개 기업의 내부망에 코드 실행을 시연해 13만 달러 이상의 버그 바운티를 받았습니다.
5. 빌드 인프라 침투
가장 정교하고 방어가 어려운 유형입니다. 패키지 소스 코드는 깨끗한데, 빌드 파이프라인이나 배포 단계에서 악성 코드가 주입됩니다. 2026년 Red Hat 사건이 주목받은 이유도 여기에 있습니다. 단일 메인테이너가 아니라 조직의 배포 체계 어딘가가 침해되면, 소스 코드 리뷰만으로는 탐지가 불가능합니다.
공격 표면 한눈에 보기
개발자 머신 레지스트리(npm) 소비자 CI/프로덕션
+--------------+ +-----------------+ +------------------+
| 소스 코드 |--publish-->| 패키지 tarball |--install->| node_modules |
| npm 토큰 | | 메타데이터 | | postinstall 실행 |
| .npmrc | | dist-tags | | 번들에 포함 |
+--------------+ +-----------------+ +------------------+
^ ^ ^
| | |
[계정 탈취] [타이포스쿼팅] [install script]
[토큰 유출] [의존성 혼동] [lockfile 우회]
| |
[빌드 인프라 침투] -- 소스와 tarball이 다른 경우 탐지 매우 어려움
핵심 통찰은 이것입니다. 소스 저장소(GitHub)와 레지스트리에 올라간 tarball은 별개의 산출물입니다. GitHub에서 코드를 리뷰해도, 실제로 설치되는 tarball에 같은 코드가 들어 있다는 보장은 어디에도 없습니다. 이 간극을 메우는 것이 뒤에서 다룰 provenance입니다.
1차 방어선 — install scripts 차단
가장 비용 대비 효과가 큰 방어부터 시작합니다. 프로젝트 루트 또는 사용자 홈의 .npmrc에 다음을 추가하세요.
.npmrc — install script 자동 실행 차단
ignore-scripts=true
부수 효과: 의존성 혼동 방어를 위한 스코프 고정
@mycompany:registry=https://npm.internal.mycompany.com/
always-auth=true
감사 수준 설정
audit-level=high
ignore-scripts를 켜면 esbuild, sharp처럼 네이티브 바이너리를 빌드하는 패키지가 동작하지 않을 수 있습니다. 이때는 전면 차단 후 화이트리스트 방식으로 풀어주는 것이 정석입니다. pnpm은 이를 일급 기능으로 지원합니다.
pnpm v10+ — pnpm-workspace.yaml
기본적으로 모든 install script 차단, 명시된 패키지만 허용
onlyBuiltDependencies:
- esbuild
- sharp
- better-sqlite3
npm을 쓴다면 ignore-scripts를 켠 채로, 필요한 패키지만 설치 후 수동 빌드하는 스크립트를 두는 방식이 현실적입니다.
{
"scripts": {
"postdeps": "npm rebuild esbuild sharp",
"deps": "npm ci --ignore-scripts && npm run postdeps"
}
}
2025년 웜 사태 이후 pnpm이 install script를 기본 차단으로 바꾼 것은 생태계 전체의 방향을 보여줍니다. 실행되는 코드의 총량을 줄이는 것이 모든 방어의 출발점입니다.
2차 방어선 — lockfile 무결성
lockfile은 단순한 버전 고정 장치가 아니라 무결성 검증 장치입니다. package-lock.json의 각 항목에는 integrity 필드가 있습니다.
{
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}
}
integrity는 tarball의 SHA-512 해시입니다. npm ci는 이 해시가 일치하지 않으면 설치를 중단합니다. 따라서 CI에서는 반드시 npm install이 아니라 npm ci를 써야 합니다. npm install은 lockfile을 조용히 갱신할 수 있지만, npm ci는 lockfile과 package.json이 어긋나면 실패하기 때문입니다.
여기에 두 가지를 더해야 lockfile 방어가 완성됩니다.
첫째, lockfile 자체의 변조를 검증합니다. PR에서 lockfile의 resolved URL이 공식 레지스트리가 아닌 곳을 가리키도록 바뀌는 공격이 실제로 보고된 바 있습니다. lockfile-lint로 차단합니다.
npx lockfile-lint \
--path package-lock.json \
--allowed-hosts npm \
--validate-https \
--validate-integrity
둘째, PR에서 의존성 변경을 사람이 볼 수 있게 만듭니다. GitHub의 dependency-review-action은 PR에 추가된 의존성의 알려진 취약점과 라이선스를 검사합니다.
.github/workflows/dependency-review.yml
name: Dependency Review
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
deny-licenses: AGPL-1.0-only, AGPL-3.0-only
3차 방어선 — provenance와 Sigstore 서명
앞서 말한 "소스와 tarball의 간극" 문제를 푸는 것이 npm provenance입니다. 2023년부터 npm은 Sigstore 기반의 provenance 증명을 지원합니다. 패키지가 어느 저장소의 어느 커밋에서, 어느 CI 워크플로로 빌드되었는지를 암호학적으로 증명하는 메타데이터입니다.
배포 측(메인테이너)은 GitHub Actions에서 다음과 같이 설정합니다.
.github/workflows/publish.yml
name: Publish Package
on:
release:
types: [published]
permissions:
contents: read
id-token: write # Sigstore OIDC 서명에 필수
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org'
- run: npm ci --ignore-scripts
- run: npm run build
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
핵심은 id-token 권한입니다. 이 워크플로는 GitHub OIDC 토큰으로 Sigstore의 Fulcio 인증서를 발급받아 서명하고, 서명 기록은 공개 투명성 로그(Rekor)에 남습니다. 장기 보관 서명 키가 아예 존재하지 않으므로, 키 유출이라는 공격 벡터 자체가 사라집니다.
소비 측에서는 설치된 패키지의 서명과 증명을 검증할 수 있습니다.
레지스트리 서명 + provenance 증명 일괄 검증
npm audit signatures
provenance의 한계도 알아야 합니다. provenance는 "이 tarball이 이 저장소의 이 커밋에서 빌드됐다"를 증명할 뿐, 그 커밋의 코드가 안전하다는 것을 증명하지 않습니다. 빌드 인프라 침투형 공격을 어렵게 만들지만, 악의적 커밋 자체를 막지는 못합니다. 또한 2026년 현재까지도 provenance를 붙여 배포하는 패키지는 전체의 일부에 불과해서, "provenance 없는 패키지 차단" 정책을 일괄 적용하기는 아직 어렵습니다.
의존성 최소화와 벤더링 논쟁
기술적 방어 이전에 구조적인 질문이 있습니다. 애초에 의존성이 이렇게 많아야 하는가?
평균적인 Node.js 프로젝트는 직접 의존성 수십 개, 전이 의존성 천여 개를 끌고 옵니다. left-pad 사태가 보여줬듯, 한 줄짜리 함수를 위해 패키지를 설치하는 문화가 공격 표면을 기하급수적으로 키웠습니다.
실무에서 쓸 수 있는 판단 기준을 정리하면 이렇습니다.
| 상황 | 권장 |
| --- | --- |
| 20줄 이내로 직접 구현 가능 | 직접 작성 (의존성 추가 금지) |
| 표준 라이브러리로 대체 가능 | Node 내장 fetch, structuredClone 등 사용 |
| 작지만 검증이 중요한 로직 | 코드를 복사해 벤더링 + 출처 주석 |
| 크고 복잡한 라이브러리 | 의존성 추가 + Scorecard 점수 확인 |
벤더링(의존성 소스를 저장소에 직접 복사)에 대한 논쟁은 HN에서 주기적으로 반복됩니다. 찬성 측은 공급망 공격 차단과 빌드 재현성을, 반대 측은 보안 패치 누락과 유지보수 부담을 지적합니다. 균형점은 명확합니다. 핵심 경로의 작은 유틸리티는 벤더링하고, 활발히 패치되는 대형 라이브러리는 자동화된 갱신 파이프라인과 함께 의존성으로 유지하는 것입니다.
새 의존성을 평가할 때는 OpenSSF Scorecard가 객관적 지표를 줍니다.
의존성 후보의 보안 위생 점검
npx @ossf/scorecard-cli --repo=github.com/sindresorhus/got
주요 체크 항목:
- Maintained: 최근 90일 내 커밋/이슈 활동
- Code-Review: PR 리뷰 강제 여부
- Signed-Releases: 릴리스 서명 여부
- Dangerous-Workflow: CI 설정의 위험 패턴
- Token-Permissions: GitHub 토큰 최소 권한
조직 차원의 방어 스택
개인의 주의력에 의존하는 보안은 반드시 실패합니다. 조직이라면 다음 4계층 스택을 권장합니다.
+----------------------------------------------------------+
| 4계층: 정책/감사 OpenSSF Scorecard, SBOM, 정기 audit |
+----------------------------------------------------------+
| 3계층: 스캐너 Socket / Snyk — 행위 기반 탐지 |
+----------------------------------------------------------+
| 2계층: 갱신 통제 Renovate 지연 정책 (숙성 기간) |
+----------------------------------------------------------+
| 1계층: 레지스트리 사내 프록시 레지스트리 (검역소 역할) |
+----------------------------------------------------------+
1계층 — 사내 프록시 레지스트리
Verdaccio, JFrog Artifactory, Sonatype Nexus 같은 프록시 레지스트리를 두면, 조직의 모든 npm 트래픽이 단일 관문을 통과합니다. 악성 패키지가 발견되면 관문에서 일괄 차단할 수 있고, 업스트림이 장애여도 캐시로 빌드가 유지됩니다.
verdaccio config.yaml (발췌)
uplinks:
npmjs:
url: https://registry.npmjs.org/
cache: true
packages:
'@mycompany/*':
access: $authenticated
publish: $authenticated
사내 스코프는 업스트림 조회 금지 — 의존성 혼동 원천 차단
'**':
access: $all
proxy: npmjs
사내 스코프 패키지에 proxy 설정을 빼는 것이 의존성 혼동 방어의 핵심입니다. 사내 이름이 공개 레지스트리로 흘러나가 조회되는 경로를 끊는 것입니다.
2계층 — Renovate 지연 정책
공급망 공격의 시간 패턴을 보면, 악성 버전이 배포된 후 발견되어 내려가기까지 보통 수 시간에서 수일이 걸립니다. 뒤집어 말하면, 새 버전을 즉시 받지 않고 일정 기간 숙성시키는 것만으로 대부분의 공격을 피할 수 있습니다.
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"minimumReleaseAge": "7 days",
"internalChecksFilter": "strict",
"packageRules": [
{
"matchUpdateTypes": ["patch", "minor"],
"minimumReleaseAge": "7 days"
},
{
"matchUpdateTypes": ["major"],
"minimumReleaseAge": "14 days"
},
{
"matchDepTypes": ["devDependencies"],
"minimumReleaseAge": "3 days"
}
],
"vulnerabilityAlerts": {
"minimumReleaseAge": "0 days"
}
}
마지막 블록이 중요합니다. 보안 패치는 지연 없이 즉시 받도록 예외를 둬야, 지연 정책이 역으로 취약점 노출 기간을 늘리는 부작용을 막을 수 있습니다.
3계층 — 행위 기반 스캐너
전통적 취약점 스캐너(CVE 데이터베이스 대조)는 알려진 취약점만 잡습니다. 공급망 공격은 알려지기 전에 피해를 입히므로, Socket처럼 패키지의 행위를 분석하는 도구가 보완재로 필요합니다. 새 버전에 갑자기 네트워크 호출, 환경 변수 접근, 난독화 코드, install script가 추가되면 PR 단계에서 경고합니다.
socket.yml — 프로젝트 루트
version: 2
issueRules:
installScripts: error
obfuscatedFile: error
envVars: warn
networkAccess: warn
shellAccess: error
4계층 — SBOM과 정기 감사
침해 사고가 났을 때 "우리가 그 패키지를 쓰고 있는가, 어느 서비스에서?"에 5분 안에 답할 수 있어야 합니다. CycloneDX나 SPDX 형식의 SBOM을 빌드마다 생성해 보관하세요.
CycloneDX SBOM 생성
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
특정 패키지 사용 여부 즉시 조회
jq '.components[] | select(.name == "compromised-pkg") | .version' sbom.json
CI에서의 격리 — 네트워크 차단 빌드
install script를 허용할 수밖에 없는 환경이라면, 실행되더라도 피해가 없도록 격리해야 합니다. 핵심은 빌드 단계의 네트워크 이그레스 통제입니다.
GitHub Actions에서는 harden-runner가 표준적인 선택입니다.
.github/workflows/build.yml
name: Hardened Build
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: block
allowed-endpoints: >
registry.npmjs.org:443
npm.internal.mycompany.com:443
github.com:443
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci --ignore-scripts
- run: npm run build
- run: npm test
egress-policy를 block으로 두면 화이트리스트 외의 모든 아웃바운드 연결이 차단되고 로그에 남습니다. 2025년 웜 사태 때 탈취 코드가 자격 증명을 외부 서버로 전송하는 단계에서 정확히 이 방어에 걸렸다는 보고가 다수 있었습니다.
셀프 호스티드 환경이라면 컨테이너 수준에서 동일한 통제를 구현합니다.
네트워크 없는 빌드 컨테이너 — 의존성은 사전 캐시 볼륨에서
docker run --rm \
--network=none \
-v "$PWD:/app" \
-v npm-cache:/root/.npm \
-w /app \
node:22-slim \
sh -c "npm ci --offline --ignore-scripts && npm run build"
npm ci --offline은 캐시에 없는 패키지를 만나면 실패하므로, 캐시 채우기(네트워크 허용, 스크립트 차단)와 빌드(네트워크 차단)를 두 단계로 분리하는 패턴이 됩니다.
추가로, CI에서 쓰는 npm 토큰 자체를 없애는 것도 중요합니다. 읽기 전용 미러를 쓰거나, 배포 단계에서만 OIDC 기반 단기 토큰을 발급받는 구조로 가면, CI가 침해되어도 탈취할 장기 토큰이 존재하지 않습니다.
사고 대응 절차
방어가 뚫렸을 때의 절차를 미리 문서화해 두지 않으면, 사고 당일에 즉흥적으로 움직이게 됩니다. 최소한의 runbook은 다음과 같습니다.
[T+0분] 탐지
- 스캐너 경고, HN/보안 공지, 또는 내부 이상 징후로 인지
- 영향 패키지명과 악성 버전 범위 확정
[T+15분] 노출 평가
- SBOM 조회: 해당 패키지를 쓰는 서비스/리포 목록 추출
- lockfile 이력 조회: 악성 버전이 실제 설치된 시점 확인
- 악성 버전의 행위 파악: 토큰 탈취형인가, 백도어형인가
[T+30분] 격리
- 사내 레지스트리에서 악성 버전 차단
- 영향 리포의 CI 파이프라인 일시 중지
- 배포된 아티팩트 중 악성 버전 포함분 식별
[T+1시간] 자격 증명 회전
- 악성 버전이 실행된 환경의 모든 시크릿 무효화
- npm 토큰, 클라우드 키, CI 시크릿, SSH 키 순서로 회전
- 토큰 탈취형이면 git push 이력과 npm publish 이력 감사
[T+1일] 복구와 사후 분석
- 안전 버전으로 고정 후 lockfile 재생성
- 타임라인 문서화, 탐지 공백 식별
- 재발 방지 항목을 방어 스택에 반영
자격 증명 회전 단계에서 흔한 실수는 "우리 코드에는 그 패키지의 함수를 안 쓰니까 괜찮다"는 판단입니다. install script형 공격은 코드 사용 여부와 무관하게 설치 시점에 이미 실행됐습니다. 설치 이력이 있다면 노출된 것으로 간주해야 합니다.
실전 체크리스트
개인 개발자용:
[ ] .npmrc에 ignore-scripts=true 설정
[ ] npm install 대신 npm ci 습관화 (CI에서는 강제)
[ ] npm 계정 2FA 활성화 (가능하면 하드웨어 키)
[ ] 로컬에 영구 npm 토큰 보관 금지 (granular token + 만료 설정)
[ ] 새 의존성 추가 전 다운로드 추이, 메인테이너, Scorecard 확인
[ ] npm audit signatures 주기적 실행
조직용:
[ ] 사내 프록시 레지스트리 도입, 사내 스코프 업스트림 차단
[ ] Renovate minimumReleaseAge 7일 이상 + 보안 패치 예외
[ ] 행위 기반 스캐너를 PR 게이트로 설치
[ ] CI 이그레스 정책 block + 화이트리스트
[ ] 빌드마다 SBOM 생성 및 보관
[ ] 배포 패키지에 provenance 서명 적용
[ ] 사고 대응 runbook 작성 및 분기별 모의 훈련
[ ] lockfile-lint + dependency-review를 필수 체크로 등록
함정과 반론 — 비판적으로 보기
이 글의 방어 스택에도 한계와 반론이 있습니다. 정직하게 짚고 넘어가겠습니다.
첫째, ignore-scripts는 만능이 아닙니다. install script를 막아도, 악성 코드가 패키지의 본체에 들어 있으면 require하는 순간 실행됩니다. install script 차단은 공격의 자동 실행 단계를 막을 뿐, 코드 자체의 신뢰 문제를 해결하지 못합니다.
둘째, 지연 정책은 확률 게임입니다. 7일 숙성은 빨리 발견되는 공격에만 유효합니다. 수개월간 잠복한 정교한 백도어(xz-utils 사건을 떠올려 보세요)에는 무력합니다. 그래도 통계적으로 npm 악성 패키지의 대부분이 며칠 내 발견된다는 점에서 비용 대비 효과는 여전히 큽니다.
셋째, 도구 스택 자체가 새로운 의존성입니다. 스캐너 벤더, 레지스트리 프록시, CI 보안 액션도 결국 제3자 코드이고 침해될 수 있습니다. harden-runner 같은 보안 도구를 검증 없이 추가하는 것은 아이러니한 일이므로, 보안 도구일수록 버전 고정(SHA 핀)과 출처 검증을 엄격히 해야 합니다.
액션은 태그가 아니라 커밋 SHA로 고정
- uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
넷째, 개발자 경험 비용이 실재합니다. 숙성 기간 때문에 신기능 버전을 즉시 못 쓰고, 네트워크 차단 빌드는 디버깅을 어렵게 합니다. 보안 정책이 우회 문화를 낳으면(개인 노트북에서 빌드해서 올리기 등) 오히려 위험이 커집니다. 정책 도입 시 예외 절차를 공식화하는 것이 중요합니다.
다섯째, 근본적으로 이것은 생태계 구조의 문제입니다. 개별 조직의 방어로는 한계가 있고, npm 레지스트리 차원의 2FA 강제 확대, provenance 기본화, install script 기본 차단 같은 구조적 변화가 병행되어야 합니다. OpenSSF와 npm이 그 방향으로 움직이고 있지만 속도는 더딥니다.
마치며
2026년의 Red Hat 사건은 "신뢰할 수 있는 벤더"라는 개념 자체를 다시 정의하게 만들었습니다. 신뢰는 이름에서 오는 것이 아니라 검증 가능한 증거(서명, provenance, 행위 분석)에서 와야 합니다.
요약하면 이렇습니다.
1. 오늘 당장: ignore-scripts와 npm ci, 2FA. 비용 거의 없이 가장 큰 공격 벡터를 줄입니다.
2. 이번 분기: Renovate 지연 정책, lockfile-lint, dependency-review, 스캐너 게이트.
3. 올해 안에: 사내 레지스트리, CI 이그레스 통제, SBOM, provenance 서명, 사고 대응 훈련.
공급망 보안은 한 번의 도입이 아니라 운영입니다. 완벽한 방어는 없지만, 공격자의 비용을 충분히 높이는 것은 가능합니다. 그리고 그 비용을 높이는 작업의 대부분은, 위에서 본 것처럼 설정 파일 몇 줄에서 시작됩니다.
참고 자료
- RedHatInsights javascript-clients 이슈 492: https://github.com/RedHatInsights/javascript-clients/issues/492
- npm provenance 공식 문서: https://docs.npmjs.com/generating-provenance-statements
- OpenSSF (Open Source Security Foundation): https://openssf.org/
- OpenSSF Scorecard: https://github.com/ossf/scorecard
- npm ci 공식 문서: https://docs.npmjs.com/cli/v10/commands/npm-ci
- Sigstore 프로젝트: https://www.sigstore.dev/
- SLSA (Supply-chain Levels for Software Artifacts): https://slsa.dev/
- lockfile-lint: https://github.com/lirantal/lockfile-lint
- Renovate 설정 옵션 (minimumReleaseAge): https://docs.renovatebot.com/configuration-options/
- Socket — 행위 기반 공급망 스캐너: https://socket.dev/
- Verdaccio 사내 레지스트리: https://verdaccio.org/
- step-security harden-runner: https://github.com/step-security/harden-runner
- Hacker News: https://news.ycombinator.com/
- GeekNews: https://news.hada.io/
현재 단락 (1/276)
2026년 6월, Hacker News 1면을 장식한 사건이 하나 있었습니다. Red Hat Cloud Services의 공식 JavaScript 클라이언트 저장소인 RedHatI...