NEWSkillSec — AI Skill 보안을 '악성코드 탐지'에서 '능력 감사'로SkillSec자세히 보기 →
보안 연구

npm 악성 패키지의 4가지 은닉 기법:난독화부터 지연 실행까지

Sectrend 리서치·2026.08.11·약 6분 소요
npm 악성 패키지의 4가지 기법과 대응 방어층
npm 악성 패키지의 4가지 기법과 대응 방어층

공격자가 풀어야 하는 문제

공개 저장소에 악성 패키지를 올릴 때 공격자가 마주하는 핵심 모순이 있습니다. 설치될 만큼은 정상으로 보여야 하고, 동시에 어느 시점에는 정상이 아닌 일을 해야 한다는 점입니다.

초기의 오염은 상당히 조악했습니다. 설치 스크립트에 curl 한 줄을 넣어 ~/.ssh를 묶어 외부로 보내는 식으로, 눈으로도 보이는 수준이었습니다. 자동 스캔이 보편화되면서 이런 검체는 몇 시간을 버티지 못하게 되었습니다. 그래서 기법이 진화합니다. 목적은 하나, 발견되는 시점을 뒤로 미루는 것입니다.

아래 4가지가 현재 가장 흔한 기술 경로이며, 자주 조합되어 사용됩니다.

1. 난독화: 사람도 기계도 읽지 못하게

가장 직접적인 발상은 악성 로직을 읽을 수 없게 만드는 것입니다. 흔한 형태로는 다층 base64 인코딩, 문자열 배열의 분해와 재조합, eval과 동적 속성 접근의 병용, 그리고 핵심 문자열을 문자 코드 배열로 쪼개 실행 시점에 이어붙이는 방식이 있습니다.

전형적인 검체에서는 소스 코드에 httpexec 같은 단어가 전혀 나타나지 않습니다. 실행 시점에 조립되기 때문입니다.

정적 검사가 놓치는 이유: 특징 문자열이나 키워드 대조에 기반한 스캔은 이어붙이기와 인코딩 앞에서 거의 무력합니다. 그리고 난독화 자체를 악성으로 단정할 수도 없습니다. 정당한 압축 산출물의 상당수도 난독화되어 있기 때문입니다.

유효한 신호: 난독화 정도가 패키지의 용도와 맞지 않음(작은 유틸리티에 3층 인코딩은 불필요), eval과 동적 문자열 조립의 병용, 빌드 산출물과 소스 저장소의 불일치.

2. 지연 실행: 설치 시점에는 아무것도 하지 않는다

두 번째 발상은 시간을 늘리는 것입니다. 악성 코드는 설치 시점에 완전히 침묵하고, 며칠 뒤, 특정 날짜, 또는 일정 사용 횟수를 넘긴 시점에야 활성화됩니다.

이는 자동 심사의 관측 창을 정확히 겨냥한 기법입니다. 대부분의 스캔은 공개 직후 짧은 시간에 이루어지고, 사람의 심사도 설치 시점의 행위만 보는 경우가 많습니다. 활성화될 무렵이면 그 패키지는 이미 수천 개의 락파일에 올라 있습니다.

유효한 신호: 기능과 무관한 시각 판정, 첫 실행 시 계수 목적으로 로컬 상태 파일을 기록하는 동작, 지연 실행 로직에 감싸인 네트워크 요청.

3. 환경 탐지: 관찰당하고 있으면 죽은 척한다

한 걸음 더 나아가면, 악성 패키지는 “지금 내가 분석당하고 있는가”를 능동적으로 판정합니다. 판정 항목에는 CI 환경인지(환경 변수 확인), 컨테이너나 가상 머신 위인지, 디버거가 붙어 있는지, 호스트명과 사용자명이 샌드박스 특징과 일치하는지, 아웃바운드 통신이 프록시를 거치는지 등이 포함됩니다.

분석 환경으로 판정되면 패키지는 완전히 정상적으로 동작합니다. 이는 동적 샌드박스 분석을 직접 무력화합니다. 샌드박스가 보는 것은 무해한 행위이고, 실제 개발자 단말에서는 다른 일이 벌어집니다.

유효한 신호: 기능과 무관한 환경 정보를 대량으로 읽음, 알려진 샌드박스 지문과의 대조 로직 존재, 환경에 따라 행위가 일치하지 않음.

4. 단계적 로딩: 첫 패키지는 깨끗하다

가장 발견하기 어려운 유형입니다. 공개되는 패키지 자체는 완전히 무해하고, 악성 페이로드는 실행 시점에 원격에서 가져옵니다.

첫 버전은 실제로 쓸 만한 도구여서 다운로드 수와 신뢰를 쌓습니다. 이후 어느 마이너 버전에 “설정 서버에서 업데이트를 가져온다”는 한 줄이 추가되고, 그때부터 악성 로직은 패키지가 아니라 서버 쪽에 존재합니다. 공격자는 언제든 켜고 끌 수 있고, 특정 대상에게만 배포할 수 있으며, 분석할 검체를 남기지 않습니다.

이것이 가장 어려운 이유: 패키지의 정적 내용은 항상 깨끗합니다. 소스를 백 번 감사해도 문제를 찾을 수 없습니다. 문제가 소스 안에 없기 때문입니다.

유효한 신호: 실행 시점에 선언되지 않은 네트워크 요청을 보냄, 외부에서 코드를 가져와 실행함, 요청 대상이 패키지 기능과 전혀 무관함.

3층 방어

이 4가지에 단일 수단으로는 대응할 수 없습니다. 조합이 필요합니다.

1층: 도입 시 정적 심사와 메타데이터 확인. 코드 스캔에 더해, 실제로는 메타데이터 신호가 더 유효한 경우가 많습니다. 패키지의 연령, 유지보수자 이력, 다운로드 수의 이상 급증, 인기 패키지와의 이름 유사도, 유지보수자 계정의 최근 변경. 상당수의 오염 패키지는 코드 분석에 들어가기 전에 메타데이터에서 허점을 드러냅니다.

2층: 행위 분석. 통제된 환경에서 실제로 설치·실행하며 파일 접근, 프로세스 생성, 네트워크 연결을 관찰합니다. 환경 탐지에 대응하려면 분석 환경을 가능한 한 실제 개발 단말에 가깝게 만들어야 하며, 이 자체가 지속적인 공방이 됩니다.

3층: 아웃바운드 트래픽 감시. 최후의 방어선이자 단계적 로딩에 가장 효과적인 층입니다. 악성 코드가 아무리 깊이 숨어도 결국 데이터를 밖으로 보내야 합니다. 개발 환경과 빌드 환경의 아웃바운드 허용 목록은 “감염되었다”를 “감염되었지만 손실은 없다”로 바꿉니다.

기업을 위한 실무 제안

먼저 내부 저장소 미러를 구축합니다. 모든 의존성을 내부 미러를 통해 가져오고, 허용 목록과 도입 심사를 결합합니다. 이 한 수는 구조적 효과를 가집니다. 오염, 의존성 혼동, 존재하지 않는 패키지라는 3종 리스크를 동시에 완화하기 때문입니다.

신규 도입 의존성에 관찰 기간을 둡니다. 공개된 지 얼마 되지 않고 다운로드 수가 아직 오르는 중인 패키지는, 운영 의존성에 넣기 전에 얼마간 기다릴 가치가 있습니다. 시간은 가장 저렴한 필터입니다.

락파일 변화를 주시합니다. 의존성 업데이트는 명시적 판단이어야 하며 빌드 시점의 우발 사건이어서는 안 됩니다. 락파일의 모든 변경은 코드 리뷰에 나타나야 합니다.

추적 가능성을 유지합니다. 어떤 패키지에 문제가 보고되었을 때 “어느 프로젝트가, 어느 버전을, 언제 도입했는지”에 몇 분 안에 답할 수 있어야 합니다. 완전한 의존성 대장과 지속적인 모니터링의 가치가 바로 여기에 있습니다.

오염은 사라지지 않습니다. 공개 저장소의 개방성이야말로 생태계 번영의 전제이기 때문입니다. 바꿀 수 있는 것은 발견의 속도와 영향의 범위입니다.

---

관련 글: 기업 오픈소스 도입 심사 제도 구축하기 · 오픈소스·SBOM 가이드의 악성 패키지 항목 · CSSA 일일 보안 인텔리전스

npm악성 패키지공급망 공격오염정적 탐지행위 분석의존성 보안
귀사의 코드베이스에서 어떻게 작동하는지 확인해 보시겠어요?데모 예약

관련 글

딥다이브

SBOM은 컴플라이언스 체크리스트 그 이상이다

많은 팀이 SBOM을 '제출할 서류'로 취급한다. 하지만 가치 있는 SBOM은 의사결정을 이끈다——어떤 취약점이 악용 가능한지, 어떤 의존성을 먼저 고칠지, 어떤 라이선스가 리스크를 안고 있는지.