내부 기술 문서 · 슬라이드 · 설계 단계

OpenSSF 악성 패키지(MAL)
RAW 수집

OpenSSF malicious-packages를 독립 RAW 자산으로 전량 수집하고, 정정·삭제는 물리 삭제가 아니라 상태 전이로 다루는 증분 파이프라인

래브라도랩스 · 데이터파트 · 2026 · 방안 1(독립 수집) · 미구현
01 · 배경

왜 이렇게 설계하나

02 · 무엇을

방안 1 — 독립 수집 (실측)

227,060건

2026-06-15 전량 수집 / 896MB

npm 94%

pypi 11,340 · rubygems 970 · nuget 773 …

OS 0건

언어 레지스트리 전용, 배포판 멀웨어 피드 없음

독립 자산

인벤토리 매핑은 이후 레이어로 분리

03 · 데이터 형태 ①

affected vs database_specific

영역정체용도
affected[]정규화된 결론매핑/적재에 사용
…malicious-packages-origins출처·감사 추적신뢰도(다중 출처)·증분

여러 피드(ghsa-malware, amazon-inspector …)가 같은 패키지를 신고해도 affected는 1개로 머지되고, 근거는 origins에 N개로 남는다.

04 · 데이터 형태 ②

ranges vs versions

형태건수비율
ranges만 (대개 introduced:0=전 버전)203,35689.6%
versions만 (특정 버전)16,7047.4%
둘 다 (일관됨)7,0003.1%
주의: versions는 불연속이 많다(예: easyascii 2.4.1, 2.4.5, 3.2.1…). min~max로 합치면 정상 버전을 오탐 → 버전당 개별 처리.
05 · 수집

RAW 수집 흐름

① clone / pullrepo가 raw 저장소
② manifesthead_commit · 생태계 카운트
③ 파싱 · RANGE 변환사내 구간 표기로
④ PRODUCT_KEYnpm=사내 해시 / 그 외 평문
⑤ 적재DEPRECATED 포함

PoC: ~/labrador/tool/openssf-malicious/collect.py (raw 확보까지).

06 · 변환

RANGE 변환 규칙

VULN_RANGE = | 구분 토큰(구간/단일버전)의 합집합

OSV 입력사내 표기비고
introduced:0(,)89%
introduced:X[X,)1,709건
introduced:A+fixed:B[A,B)33건 · 필수
introduced:A+last_affected:B[A,B]128건
versions:[…]v1|v2|v3합치기 금지
range 다중(한 product)union 단순화747건

ecosystem 정규화: Packagist→COMPOSER, crates.io→CARGO, Go→GOLANG … 대문자 코드. 케이싱은 UPPER() 흡수, vscode/git 스킵.

07 · 증분 (핵심)

폐기는 삭제가 아니다

advisory 정정 시: MAL-xxxx가 처음 패키지 A → 재분석 후 패키지 B로 바뀜.

B (새 상태)INSERT · DEPRECATED=0
A (옛 상태)DEPRECATED=1 (소프트삭제)
물리 삭제 금지: 데이터가 배포(distribution) DB로 동기화되어 흐른다. 지우면 sync 정합이 깨짐 → A는 지우지 않고 상태만 전이.

기준점 복구: prev 유효성 = merge-base --is-ancestor / 무효 시 commit_time 이하(≤) base / 최후엔 full reconcile(HEAD 트리 ↔ DB 활성 행 대조, 주기 self-heal).

08 · 노출

DEPRECATED 컬럼 + 활성 뷰

09 · 다음

남은 과제

정본: human/reports/2026-malicious-package-collection.md · 결정: ai/decisions/2026-06-15-malicious-package-openssf-collection.md

01