yd-cve-check · git:20261024.27d9360 · 2026-10-24 · sha256 b7d71e48d79301e5
yd-cve-check git:20261024.27d9360A
Immutable. This exact content never changes and is served at /api/v1/blob/b7d71e48d79301e5.
--- name: yd-cve-check description: pnpm 프로젝트 의존성을 알려진 CVE·GHSA·악성 패키지(MAL) 데이터와 대조해 취약 버전을 찾고, package.json 지정자 상향과 범위를 묶은 overrides 로 보완한 뒤 재스캔으로 확인한다. "pnpm 취약점 점검", "CVE 체크", "보안 패치 올려줘", "audit 고쳐줘", "취약점 점검 및 보완" 요청이나 폐쇄망에서 OSV 덤프로 오프라인 점검할 때 사용한다. 소스 코드 보안 점검은 security-precheck, 빌드·번들 설정은 yd-frontend-build 가 맡는다. --- # yd-cve-check 온디맨드로 부른다. 사용자가 "pnpm 취약점 점검 및 보완"이라고 하면 아래 절차를 끝까지 수행한다 — 점검만 하고 멈추지 않는다. 단, breaking 업그레이드와 패키지 제거는 사용자 확인을 받는다. ## CVE 목록은 스킬에 넣지 않는다 알려진 취약점은 **실행 시점의 DB를 조회해** 얻는다. 스킬에 목록을 박아 두면 다음 날 낡는다 (2026-10-24 OSV npm 덤프는 그날 04:48 UTC 에 갱신됐다). 원천은 둘이다. | 모드 | 원천 | 언제 | |---|---|---| | 온라인(기본) | `pnpm audit --json` — npm 레지스트리 advisory(GHSA) | 레지스트리에 닿을 때 | | 오프라인 | OSV npm 덤프 `https://osv-vulnerabilities.storage.googleapis.com/npm/all.zip` (약 219MB) | 폐쇄망·사내 미러만 있을 때. 덤프를 반입해 `--osv-db` 로 준다 | OSV 덤프는 GHSA 와 함께 **MAL-(악성 패키지) 항목**도 담는다. `pnpm audit` 는 악성 패키지를 잡지 못할 수 있으니, 폐쇄망이 아니어도 공급망 사고가 의심되면 OSV 덤프로 한 번 더 돌린다. 같은 락파일에서 두 모드의 CVE 목록은 일치했다(axios 0.21.0·lodash 4.17.15 실측). OSV 덤프 스캔은 약 9초 걸린다. ## 절차 1. **스캔** — 락파일이 있는 디렉터리에서 이 스킬 폴더의 `scripts/cve_scan.py` 를 실행한다. ```bash python3 <skill>/scripts/cve_scan.py # 온라인: pnpm audit python3 <skill>/scripts/cve_scan.py --osv-db all.zip # 오프라인: OSV 덤프 python3 <skill>/scripts/cve_scan.py --json # 기계 판독 ``` 종료 코드: 0 = 발견 없음, 1 = 발견 있음, 2 = 입력 오류. 심각도 미상은 기준과 무관하게 실패로 센다. 지원 락파일: `pnpm-lock.yaml` v6·v9 (직접/전이 구분은 `importers` 로 한다). 2. **직접 의존성부터 올린다** — `action=bump` 항목은 해당 `package.json` 의 지정자를 `spec` 값(`^<고정 버전>`)으로 바꾼다. 직접 의존성(bump)부터 올리고 재스캔한다 — 전이 항목은 대개 함께 사라진다. 실측: express 4.17.1 → `^4.20.0` 하나로 전이 취약 6건(body-parser·qs·path-to-regexp·send·cookie·serve-static)이 모두 사라졌다. 3. **남은 전이 의존성만 overrides** — 스캐너가 출력하는 같은 줄 범위 overrides 를 `pnpm-workspace.yaml` 의 `overrides:` 에 넣는다. 키는 `name@>=<줄 하한> <고정 버전>`, 값은 `^<고정 버전>` — 다른 메이저 사본까지 끌어올리지 않는다. 4. **breaking 은 묻는다** — 고정 버전이 다른 줄(메이저, 0.x 는 마이너)이면 `breaking=예` 로 나온다. 사용자 확인 없이 올리지 않는다. 변경 내역(CHANGELOG)·마이그레이션 문서를 확인해 영향을 같이 보고한다. 5. **설치·재스캔·검증** — `pnpm install` 후 스캐너를 다시 돌려 0건(또는 합의한 예외만)이 될 때까지 2~4 를 반복한다. 이어서 프로젝트의 타입체크·테스트·빌드를 돌린다. 고친 뒤 재스캔을 생략하지 않는다. 6. **보고** — 이전 → 이후 버전, 고친 CVE, 남은 항목과 이유(고정 없음·breaking 보류)를 표로 남긴다. 커밋은 이슈 번호와 함께. ## 실측 함정 (pnpm 10.33.0, 2026-10-24) - `pnpm audit --fix` 를 그대로 쓰지 않는다. help 는 package.json 에 쓴다고 하지만 실제로는 `pnpm-workspace.yaml` 에 쓴다. 또 advisory 마다 상한 없는 `>=` 오버라이드를 하나씩 추가해, axios 0.21.0 이 1.20.0 으로 메이저가 바뀌었다. 직접 의존성의 지정자까지 `>=0.28.0` 처럼 덮어썼다. - advisory 의 최소 고정 버전도 안전하다는 보장이 없다. axios 0.21.0 에 대해 `pnpm audit` 이 가리킨 0.33.0 은 0.21.0 이후에 생긴 advisory 2건(GHSA-9fr6-4gfg-395g, GHSA-x97p-jq2g-jp4f, 0.34.0 에서 고정)에 걸린다. OSV 모드는 패키지의 모든 advisory 로 목표 버전을 다시 검사해 0.34.0 을 낸다. 온라인 모드는 재스캔이 이 검사를 대신한다. - 0.x 의 caret 은 마이너를 고정한다. `^0.33.0` 은 0.34.0 을 받지 않는다. ## 특수 항목 - **MAL-(악성 패키지)** — 버전을 올리지 말고 제거한다. 설치된 적이 있으면 그 머신의 토큰·자격증명을 교체하라고 보고한다. - **고정 버전 없음(no-fix)** — 대체 패키지를 찾거나, 근거와 재검토 날짜를 남기고 `pnpm-workspace.yaml` 의 `auditConfig.ignoreGhsas` 에 등록한다. 스캐너는 `--ignore <GHSA|CVE>` 로 같은 예외를 받는다. 근거 없는 무시는 하지 않는다. ## 재발 방지 설정 (pnpm 10.33.0 소스에서 확인) 보완을 마치면 아래를 `pnpm-workspace.yaml` 에 제안한다. 적용은 사용자 결정이다. | 설정 | 효과 | |---|---| | `minimumReleaseAge: 1440` | 공개 후 1440분(하루)이 안 된 버전은 설치하지 않는다 — 탈취된 새 버전을 피하는 시간 완충. 단위는 분 | | `trustPolicy: no-downgrade` | 이전 버전보다 신뢰 근거(provenance 등)가 약해진 버전을 거부한다 | | `blockExoticSubdeps: true` | 전이 의존성이 git·tarball URL 같은 레지스트리 밖 출처를 쓰면 거부한다 | | `onlyBuiltDependencies` | pnpm 10 은 의존성 설치 스크립트를 기본 차단한다(esbuild 0.24.0 설치 시 "Ignored build scripts" 실측). 허용은 `pnpm approve-builds` 로 골라 이 목록에 둔다. `dangerouslyAllowAllBuilds` 는 쓰지 않는다 | ## 하지 않는 것 - CVE 목록을 이 스킬 파일에 복사해 두지 않는다. - `pnpm audit --fix` 결과를 검토 없이 커밋하지 않는다. - 상한 없는 `>=` 오버라이드를 쓰지 않는다. - 스캔 결과에 토큰·레지스트리 자격증명(`.npmrc` 값)을 출력하지 않는다.