pnpm으로 공급망 공격 방어하기
소프트웨어 공급망 공격(Software Supply-Chain-Attack) 증가 추세 속에서, 개발 과정의 외부 자산(External Assets) 침해를 통한 우회 공격 기법이 주목받고 있음
Axios 패키지 사례처럼 간접 의존성(Transitive Dependency) 트리 오염 및 npm lifecycle scripts 악용으로 인한 비밀 키 유출 사고 발생
인프랩은 pnpm 11의 Cool-Down 및 임의 코드 실행 차단 기능을 도입하여 공급망 공격에 대한 1차 방어선 구축을 강화함
npm lifecycle scripts 악용 방식 분석
Axios 공급망 공격 사례는 npm lifecycle scripts의 취약점을 명확히 보여줍니다. 공격자는 악성 패키지인 `plain-crypto-js`를 `axios`의 간접 의존성에 주입하고, `postinstall` 스크립트를 통해 사용자 모르게 악성 코드를 실행시켰습니다. 이 스크립트는 `npm install` 시점에 자동으로 실행되어, 분석 환경 탐지, 민감 정보 수집, C2 서버 전송, 흔적 은폐까지 수행하는 전형적인 자격증명 탈취형 드로퍼(Credential-Stealing Dropper) 역할을 했습니다. 특히, `package.json`의 `postinstall` 항목에 악성 스크립트를 숨겨 개발자의 직접적인 코드 실행 없이 공격이 이루어졌다는 점이 심각한 문제입니다.
pnpm 11의 공급망 공격 방어 메커니즘
pnpm 11은 Cool-Down과 임의 코드 실행 차단이라는 두 가지 핵심 전략으로 공급망 공격에 대응합니다. `minimumReleaseAge` 설정은 신규 게시된 버전에 대해 일정 시간(기본 24시간)의 설치 지연을 강제하여, 보안 커뮤니티의 탐지 및 신고 시간을 확보합니다. `strictDepBuilds`는 의존성 패키지의 빌드 스크립트 실행을 기본적으로 차단하여, `postinstall` 스크립트를 통한 악성 코드 실행을 원천 봉쇄합니다. 이 두 기능은 안전하지 않은 버전의 자동 전파를 지연시키고, 예상치 못한 코드 실행을 방지하는 강력한 1차 방어선 역할을 수행합니다.
pnpm의 trustPolicy와 신뢰 수준 관리
pnpm의 `trustPolicy: no-downgrade` 설정은 패키지 게시 방식에 따른 신뢰 수준 하락을 감지하여 설치를 차단합니다. Axios 공격 사례처럼, 공격자가 npm CLI를 통해 수동으로 게시하여 신뢰 수준을 `Trusted Publisher`에서 `None`으로 낮추는 경우, 이 정책은 즉각적으로 작동하여 악성 버전의 설치를 방지합니다. 이는 게시자 신원 및 빌드 출처 검증이 불확실한 패키지가 시스템에 침투하는 것을 막는 중요한 보안 장치입니다. 신뢰 수준 하락을 감지하는 것은 공급망의 무결성(Integrity)을 유지하는 데 필수적입니다.
strictDepBuilds와 allowBuilds의 역할
`strictDepBuilds: true`는 기본적으로 모든 의존성 패키지의 빌드 스크립트 실행을 차단하여 보안을 강화합니다. 하지만 `esbuild`나 `sharp`와 같이 네이티브 바이너리 컴파일을 위해 빌드 스크립트가 필수적인 패키지의 경우, `allowBuilds` 설정을 통해 해당 패키지에 한해 명시적으로 빌드 스크립트 실행을 허용할 수 있습니다. 이는 공격 표면(Attack Surface)을 최소화하면서도 정상적인 빌드 프로세스를 유지하는 균형 잡힌 접근 방식입니다. `dangerouslyAllowAllBuilds: true`는 `strictDepBuilds`의 의미를 무력화하므로 사용하지 않는 것이 권장됩니다.
pnpm 마이그레이션 전략 및 고려사항
기존 `npm`이나 `yarn` 사용자는 `pnpm import` 명령으로 기존 잠금 파일을 기반으로 `pnpm-lock.yaml`을 생성하여 마이그레이션을 시작할 수 있습니다. 이미 `pnpm`을 사용 중이라면, 메이저 버전별 마이그레이션 가이드를 따라 단계적으로 업데이트하는 것이 권장됩니다. 예를 들어 `pnpm 8`에서 `11`로 바로 점프하기보다 `8 → 9 → 10 → 11` 순서로 진행하면, 각 단계별 변경 사항을 검증하고 잠금 파일(Lock File) 및 의존성 해석 방식의 잠재적 문제를 조기에 발견하여 디버깅 부담을 줄일 수 있습니다.