블로그
home
Nation-State Cyber Actors Analysis Report
home

Trivy 공급망 공격(CVE-2026-33634)을 통한 개발도구 공급망 연쇄 공격 관련 악성코드 분석

작성자
김경렬
감수인
작성일
2026/04/03
배포일
2026/04/17
문서등급
TLP:CLEAR
Tags
Supply Chain
Trivy
LiteLLM
Checkmarx
Telnyx
PyPI
NPM
Github
문서유형
Analysis Report

01. Executive Summary

사건개요
2026.03.19 (UTC) 개발·보안 환경에서 사용되는 오픈소스 보안 스캐너인 Trivy의 공급망이 침해되어 공식 배포 채널을 통해 악성 버전의 파일 배포
CI/CD 파이프라인에서 실행된 악성 Trivy가 탈취한 자격증명 정보들을 기반으로 NPM, PyPI, OpenVSX, Github Actions 등 다수의 생태계를 연쇄적으로 감염시킨 공급망 공격 사례
악성 파일은 ‘환경변수 기반 정보ʼ, ‘Git/SSH 자격증명ʼ, ‘클라우드 자격증명(AWS, GCP, Azure)ʼ, ‘쿠버네틱스 설정ʼ, ‘암호화폐 지갑 정보ʼ, ‘DB 관련 정보ʼ, ‘CI/CD설정’, ‘로컬 계정 정보’ 등 각종 자격증명 정보 탈취
Trivy 공급망 공격(CVE-2026-33634)를 시작으로 연쇄적인 공급망 공격이 발생됨에 따라 시간 흐름에 따라 5개의 피해 사례별로 분석 진행
(공격흐름) : ① Trivy 공급망 공격(CVE-2026-33634) → ② NPM CanisterWorm 확산 → ③ Checkmarx/OpenVSX → ④ LiteLLM PyPI 감염 → ⑤ Telnyx PyPI 감염
대응방안
(감염 여부 점검)
자동화 파이프라인에서 하기 노출 시간 동안 다운로드, 설치, 또는 실행한 아티팩트 유무 점검 필요
구분
대상
노출 시간 (UTC)
노출 시간 (KST)
Aqua / Trivy
Trivy v0.69.4
2026-03-19 18:22 ~ 21:42
2026-03-20 03:22 ~ 06:42
Aqua / GitHub Action
trivy-action
2026-03-19 17:43 ~ 2026-03-20 05:40
2026-03-20 02:43 ~ 14:40
Aqua / GitHub Action
setup-trivy
2026-03-19 17:43 ~ 21:44
2026-03-20 02:43 ~ 06:44
Aqua / Docker Hub
trivy v0.69.5, v0.69.6
2026-03-22 15:43 ~ 2026-03-23 01:40
2026-03-23 00:43 ~ 10:40
Checkmarx / GitHub Action
kics-github-action ast-github-action
2026-03-23 12:58 ~ 16:50
2026-03-23 21:58 ~ 2026-03-24 01:50
Checkmarx / OpenVSX
ast-results-2.53.0.vsix cx-dev-assist-1.7.0.vsix
2026-03-23 02:53 ~ 15:41
2026-03-23 11:53 ~ 2026-03-24 00:41
LiteLLM / PyPI
LiteLLM v1.82.7, v1.82.8
2026-03-24 10:39 ~ 16:00
2026-03-24 19:39 ~ 2026-03-25 01:00
Telnyx / PyPI
Telnyx v4.87.1, 4.87.2
2026-03-27 03:51:28 ~ 10:13
2026-03-27 12:51:28 ~ 19:13
NPM
[별첨] Trivy 공급망 공격 영향 대상 목록 참고
-
-
시스템에 연결된 Github 계정에 tpcp-docs 리포지터리 생성 여부 확인
감염 추정 시 영향 받은 아티팩트 즉시 삭제 후 안전한 버전으로 업데이트, 잠정 노출된 자격 증명 정보 및 비밀번호 교체
(시스템 이상 여부 점검)
하기 파일 발견 시 즉시 삭제
파일
~/.local/share/pgmon/service.py
~/.config/sysmon/sysmon.py
/tmp/pglog
/tmp/.pg_state
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\msbuild.exe
서비스
~/.config/systemd/user/pgmon.service
~/.config/systemd/user/sysmon.service
(네트워크 통신 확인) : IoC 정보 참고하여 통신 이력 점검

02. Background

2.1. 주요 타임라인

공격 대상
일자 (UTC)
내용
출처
Trivy
2026년 2월 말 ~ 2026.03.01
• 공격자가 Trivy의 GitHub Actions 환경의 잘못된 구성 설정을 악용하여 권한 있는 액세스 토큰을 탈취하여 저장소 자동화 및 릴리스 프로세스에 대한 접근 권한 확보 • Trivy에서 사고 확인 후 자격 증명 정보 교체 작업을 수행했으나, 교체가 완전히 동시에 이루어지지 않아서 공격자가 새로운 유효한 자격 증명 정보를 확보했을 가능성 제기
Trivy
2026.03.19
• 공격자는 탈취한 자격 증명을 악용하여 악성 버전인 Trivy v0.69.4를 릴리스하고 aquasecurity/trivy-action 76/77개 태그, aquasecurity/setup-trivy 기존 태그 7개 (v0.2.0~v0.2.6)를 모두 악성 Commit으로 푸시 • checkmarx[.]zonemodels.litellm[.]cloud 악성 C2 도메인 등록
NPM
2026.03.20 ~
• 공격자가 탈취한 NPM 자격증명을 이용해 NPM에 자기전파형 웜(CansiterWorm)을 유포하여 @EmilGroup 28종, @opengov 16종, 기타 스코프 패키지 등 총 66개 이상의 패키지 감염
Trivy
2026.03.22
• 공격자가 별도로 탈취한 Docker Hub 자격증명을 이용해 GitHub 릴리스 없이 aquasec/trivy:0.69.5, v0.69.6 도커 이미지 직접 푸시
Checkmarx / OpenVSX
2026.03.23
• Checkmarx의 kics-github-action, ast-github-action 및 OpenVSX 확장 프로그램 2종(cx-dev-assist 1.7.0ast-results 2.53.0)에서 악성코드 감염 정황 발견
LiteLLM
2026.03.24
• PyPI의 LiteLLM v1.82.7, v1.82.8 패키지에서 악성코드 감염 정황 발견
Trivy
2026.03.26
• 미국 CISA에서 해당 취약점(CVE-2026-33634)을 KEV(Known Exploited Vulnerability)에 등재
Telnyx
2026.03.27
• PyPI의 Telnyx v4.87.1, v4.87.2 패키지에서 악성코드 감염 정황 발견
Trivy
2026.03.27
• 싱가포르 CSA에서 해당 캠페인을 “Ongoing 'TeamPCP' Supply-Chain Campaign”으로 추적

2.2. TeamPCP 정보

이번 캠페인에서 TeamPCP Cloud Stealer 사용 흔적이 발견되어 공격자를 TeamPCP로 추적중
2026년 2월 Flare의 보고서에서 언급된 TeamPCP(PCPcat, ShellFoce, DeadCatx3)는 2025년 12월부터 클라우드 네이티브 환경을 대상으로 하는 대규모 공격 수행
웜을 이용하여 노출된 Docker API, Kubernetes 클러스터, Ray 대시보드, Redis 서버, React2Shell 취약점 등 악용
X(https://x.com/pcpcats)에서 @pcpcats 계정으로 활동중이며 Telegram, Data Leak Site 운영 사례도 발견되었으나 현재는 접근 불가능
Data Leak Site의 경우 CIPHERFORCE 랜섬웨어 그룹의 사이트를 같이 사용하고 있어 두 그룹이 같은 계열사이거나 협업하는 것으로 추정 중
TeamPCP X 정보
TeamPCP Data Leak Site 정보 (출처 : TrendMicro)

03. Trivy 공급망 공격(CVE-2026-33634) 세부 설명

(주요 원인)
이번 침해는 2026년 2월 말에 발생한 공격의 연장선으로 당시 공격자는 GitHub Actions 환경 설정 문제를 악용해 privileged token 탈취
잘못 구성된 GitHub Actions workflow를 악용하였고, 해당 workflow는 저장소 비밀 정보에 대한 접근 권한을 보유한 상태
3월 1일 사건 공개 이후 Trivy 측에서 자격 증명 교체 작업을 수행했지만 모든 자격 증명이 동시에 폐기되지 않았음
공격자가 유효한 토큰을 사용하여 교체 기간 동안 새로 교체된 비밀 키를 유출했을 가능성이 있으며, 이로 인해 공격자가 접근 권한을 보유한 채로 3월 19일에 공격을 실행한 것으로 추정
(공급망 공격 과정)
Trivy v0.69.4 침해
actions/checkout의 참조를 가짜 Commit(70379aad)으로 바꾸는 (1885610c) Commit을 Push
가짜 Commit에는 타이포스쿼팅된 도메인으로부터 악성 Go 소스 파일을 다운로드하는 작업이 포함됨
goreleaser가 바이너리 유효성 검사를 통과할 수 있도록 -skip=validate 추가한 commit을 v0.69.4로 태깅 후 Release 파이프라인 실행
해당 release는 Trivy의 정규 배포 채널인 GHCR, ECR Public, Docker Hub(0.69.4, latest 태그 둘다), deb/rpm packages, get.trivy.dev등을 통해 배포
공격자가 v0.70.0 악성 버전 배포를 시도했으나 이는 사전에 차단
trivy-action 태그 하이재킹
공격자는 77개의 버전 태그 중 76개를 악성 Commit에 강제로 푸시하여 entrypoint.sh에 Infostealer를 Injection
삽입된 악성코드는 정상 Trivy scan 보다 먼저 실행되어 악성 행위 수행
setup-trivy 릴리스 교체 작업 수행
기존 태그 7개 (v0.2.0~v0.2.6) 모두 악성 Commit으로 강제 푸시
교체된 악성 action.yaml에는 trivy-action에서와 동일한 Infostealer가 정식 Trivy 설치 전에 실행되는 환경 설정(Setup environment) 단계에 삽입
Trivy v.0.69.5, v0.69.6 도커 이미지 배포
공격자는 v0.69.4 버전에 사용된 것과 동일한 C2 도메인을 사용하는 aquasec/trivy:0.69.5 and aquasec/trivy:0.69.6 페이로드 생성
별도로 탈취한 Docker Hub 자격 증명 정보를 이용해 Github을 거치지 않고 Docker Hub에 직접 푸시하여, 이와 관련한 Github 태그나 릴리스는 존재하지 않음
(악성코드 동작 과정)
1.
Github Runner 관련 프로세스별 env, ssh 등 자격 증명 정보 수집하여 시스템 환경(GitHub Hosted Runners / Self Hosted Runners) 식별
2.
식별된 환경에 따라 추가 동작 수행
GitHub Hosted Runner 환경 : GitHub Actions Runner.Work 프로세스 메모리 덤프 Python Script 실행
Self Hosted Runner 환경
(trivy) : 지속성 유지 및 추가 작업을 위한 sysmon.py 등록 및 실행
(trivy-action, setup-trivy) : 각종 자격 증명 정보를 수집하는 TeamPCP Cloud Stealer 실행
3.
수집한 정보가 담긴 파일은 하이브리드 암호화(수집 데이터는 AES-256-CBC 암호화, 세션 키는 RSA-4096 공개키로 암호화) 수행하여 tpcp.tar.gz 파일로 생성 후 C2에 전송
C2에 데이터 전송 실패 시 탈취한 GitHub PAT(Personal Access Token) 이용하여 GitHub에 tpcp-docs 저장소 생성 후 탈취 데이터 업로드 절차 수행

3.1. Trivy 관련 악성코드 분석: Trivy v0.69.4 상세 분석

1) Trivy v0.69.4

각종 자격 증명 정보 수집 → 환경(GitHub Hosted Runner / Self Hosted Runner)에 따른 추가동작 결정 → 수집 데이터 하이브리드 암호화(AES-256-CBC 방식 암호화, 세션 키는 RSA-4096 공개키로 암호화) 수행 후 C2로 정보 탈취
동작 과정
Go 언어로 작성된 ELF 파일로 정상 Trivy 실행 전에 악성 코드가 추가되어 _SCAND 라는 환경변수를 확인하여 1 이라는 값 확인 시 동작
악성 행위 수행 부분
현재 쉘 프로세스 PID 및 GitHub Actions Runner* 관련 프로세스(Runner.Worker, Runner.Listener, runsvc, run.sh) PID 수집
GitHub Actions는 GitHub 안에서 돌아가는 자동화 서비스이고, GitHub Actions Runner는 그 자동화를 실제로 실행하는 머신/프로세스
각 대상 pid 별로 /proc/<pid>/environ 내용 확인 후 env 또는 ssh 포함된 값 수집
환경변수의 값이 실제 파일을 가리킬 경우에는 해당 파일 내용도 수집
각종 자격 증명 정보 수집
npm·PyPI·GitHub 토큰, SSH 키, 클라우드 인증정보(AWS, GCP, Azure), .env 파일, 쿠버네틱스 설정, 암호화폐 지갑정보(비트코인, 이더리움, 솔라나 등 10종), DB 인증정보, CI/CD 설정 등
Github Runner 환경인지 확인하여 환경에 따라 다른 파이썬 스크립트 실행
Github Hosted Runner 환경인 경우 : GitHub Actions Runner.Work 프로세스 메모리 덤프 파이썬 스크립트 실행
Github Hosted Runner 환경이 아닌 경우(Self Hosted Runner 환경인 경우) : 지속성 유지 및 추가 작업을 위한 파이썬 스크립트(sysmon.py) 및 서비스(system.service) 설치 및 실행
수집 데이터 존재 시 AES-256-CBC 방식 암호화, 세션 키 파일은 RSA-4096 공개키로 암호화하는 하이브리드 암호화 수행하여 C2(https://scan.aquasecurtiy[.]org)로 정보 탈취
rand를 이용해 세션키로 사용할 32바이트 랜덤 값 생성
수집 데이터를 AES-256-CBC 방식으로 암호화하여 payload.enc 파일 생성
세션키를 PassPhrase로 사용해 PBKDF2 기반 AES Key, IV 파생하여 적용
세션키는 하드코딩된 공개키를 이용해 OAEP 패딩 모드의 RSA 암호화하여 session.key.enc 파일로 저장
탈취 데이터 전송 실패 시(응답코드가 2xx가 아닌 경우) 환경변수에 INPUT_GITHUB_PAT존재 시 PAT(Personal Access Token) 이용하여 GitHub에 업로드 절차 수행
1.
GitHub Personal Access Token(PAT) 존재 시 GitHub API를 이용해 tpcp-docs라는 공개 저장소 생성 시도
2.
PAT 소유자의 GitHub username 조회 후 현재 시각 기반 tag(data-20060102150405)로 release 생성
3.
앞서 생성한 tpcp.tar.gz 파일을 release asset으로 업로드
탈취 데이터 전송 실패 시 동작

2-1) Github Hosted Runner 기반 Python Script

Github Hosted Runner 환경인 경우 실행되는 GitHub Actions Runner.Work 프로세스 메모리 덤프 파이썬 스크립트(MD5: 818271154971537a9b52e908b1463508)
Trivy-Action에서 사용된 파일과 동일한 기능을 수행하며 코드 작성법에서 차이
Runner.Worker에 해당하는 /proc 발견 시 pid 정보 수집하여, 해당 pid의 /proc/{pid}/maps, /proc/{pid}/mem 접근
maps를 읽으면서 읽기 가능한 메모리 영역만 해당 영역의 시작-끝 주소를 mem에서 읽은 후 stdout으로 출력
Github Hosted Runner 환경 프로세스 메모리 덤프 파이썬 스크립트

2-2) Self Hosted Runner 기반 Python Script - sysmon.py(Persistence)

Github Runner 환경이 아닌 Self Hosted Runner 환경인 경우 지속성 유지 및 추가 작업을 위해 사용하는 페이로드
CanisterWorm에서 사용하는 service.py와 동일한 파일
동작 과정
1.
최초 1회 300초(5분) 대기
2.
C2에 접속하여 응답 데이터를 읽어왔을 때 "http"로 시작하면 URL로 판단하여 그대로 반환, 아닐 경우 None 반환
C2(C_URL) : https://tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0[.]io/
해당 C2는 ICP Canister(tdtqy-oyaaa-aaaae-af2dq-cai)에 접근하는 주소로, 평소에는 정상 유튜브 링크를 작성하고 악성 페이로드 사용 시에 C2 도메인으로 교체하여 사용하는 것으로 추정
분석 시점 기준 해당 도메인은 접속 불가이며 VirusTotal 조회 시 발견된 시점에는 정상 유튜브 링크가 작성되었던 것으로 확인
3.
C2에서 읽어온 URL 주소가 이전에 접근한 주소와 다르고 URL 내에 “youtube.com”(킬 스위치 목적)이 들어가 있지 않은 경우에 동작 수행
전달받은 URL에서 파일 다운로드하여 TARGET(/tmp/pglog)에 저장 후 실행권한 755 부여하고 분리된 세션으로 실행
접근했던 URL은 STATE(/tmp/.pg_state)에 기록
4.
3000초(50분) 대기 후 과정 2~3 반복
sysmon.py 내용

3.2. Trivy 관련 악성코드 분석: trivy-action 상세 분석

1) entrypoint.sh

각종 자격 증명 정보 수집 → 환경(GitHub Hosted Runner / Self Hosted Runner)에 따른 추가동작 결정 → 수집 데이터 하이브리드 암호화(AES-256-CBC 방식 암호화, 세션 키는 RSA-4096 공개키로 암호화) 수행 후 C2로 정보 탈취
동작 과정
현재 쉘 프로세스 PID 및 GitHub Actions Runner 관련 프로세스(Runner.Worker, Runner.Listener, runsvc, run.sh) PID 수집하여 /tmp/runner_collected_<pid>.txt 파일에 저장
각 대상 pid 별로 /proc/<pid>/environ 내용 확인 후 env 또는 ssh 포함된 값 수집
환경변수의 값이 실제 파일을 가리킬 경우에는 해당 파일 내용도 수집
시스템이 Github Hosted Runner 환경인지 여부에 따라 다른 파이썬 스크립트를 실행하여 각각 다른 데이터 수집
수집한 데이터는 /tmp/runner_collected_<pid>.txt 파일에 저장
1.
Github Hosted Runner 환경인 경우 : GitHub Actions Runner.Work 프로세스 메모리 덤프 파이썬 스크립트 실행
파이썬 실행 결과 반환되는 runner 메모리 또는 내부 구조에서 isSecret: true 형태의 secret 객체 직접 복원 시도
2.
Github Hosted Runner 환경이 아닌 경우(Self Hosted Runner 환경) : TeamPCP Cloud Stealer 파이썬 스크립트 실행하여 각종 자격증명 정보 수집
수집 데이터 파일은 AES-256-CBC 방식 암호화, 세션 키 파일은 RSA-4096 공개키로 암호화하는 하이브리드 암호화 수행하여 C2(https://scan.aquasecurtiy[.]org)로 정보 탈취
openssl rand를 이용해 32바이트 랜덤 값(session.key) 생성
수집 데이터를 AES-256-CBC 방식으로 암호화하여 payload.enc 파일 생성
session.key를 PassPhrase로 사용해 PBKDF2 기반 AES Key, IV 파생하여 적용
session.key는 하드코딩된 공개키가 저장된 파일 p(public key)를 이용해 OAEP 패딩 모드의 RSA 암호화하여 session.key.enc 파일로 저장
payload.enc, session.key.enc 파일을 압축하여 tpcp.tar.gz 파일 생성 후 C2(https://scan.aquasecurtiy[.]org)로 전송하여 데이터 탈취
탈취 데이터 전송 실패 시(응답코드가 2xx가 아닌 경우) 환경변수에 INPUT_GITHUB_PAT존재 시 PAT(Personal Access Token) 이용하여 GitHub에 업로드 절차 수행
1.
GitHub Personal Access Token(PAT) 존재 시 GitHub API를 이용해 tpcp-docs라는 공개 저장소 생성 시도
2.
PAT 소유자의 GitHub username 조회 후 현재 시각 기반 tag(data-YYYYMMDDHHMMSS)로 release 생성
3.
앞서 생성한 tpcp.tar.gz 파일을 release asset으로 업로드
entrypoint.sh (MD5 : d761a6a7ae9f2254bd81ac234033a8b8) 내용

2-1) Github Hosted Runner Linux 기반 Python Script

Github Hosted Runner 환경인 경우 실행되는 GitHub Actions Runner.Work 프로세스 메모리 덤프 파이썬 스크립트(MD5: c77d1f7b23732cd8a958487ac92438e6)
Runner.Worker에 해당하는 /proc 발견 시 pid 정보 수집하여, 해당 pid의 /proc/{pid}/maps, /proc/{pid}/mem 접근
maps를 읽으면서 읽기 가능한 메모리 영역만 해당 영역의 시작-끝 주소를 mem에서 읽은 후 stdout으로 출력
GitHub Actions Runner.Work 프로세스 메모리 덤프 파이썬 스크립트 내용

2-2) Self Hosted Runner 기반 Python Script

Github Runner 환경이 아닌 Self Hosted Runner 환경인 경우 실행되는 TeamPCP Cloud Stealer(MD5: 9f6075c462ca52dc56e5fce10328ac3b)
피해 시스템 환경에서 각종 자격 증명 정보를 수집하는 악성코드
코드 하단의 주석에서 TeamPCP Cloud Stealer라는 문자열 확인
수집 대상

3.3. Trivy 관련 악성코드 분석: setup-trivy 상세 분석

1) action.yaml

setup-trivy는 Github Actions workflow에서 호출해서 사용하는 설치용 action이며, runner가 action.yaml에 정의된 step들을 순차 실행하여 Trivy 바이너리 설치 및 후처리 수행
action.yaml 파일의 Setup Environment 단계에 악성 코드가 삽입되어 runner 환경의 자격증명 및 민감정보 탈취 행위 수행
삽입된 코드는 trivy-action의 entrypoint.sh와 동일한 코드로 확인되어 이후 세부 동작 과정은 해당 내용 참고
변경 내용

04. NPM CanisterWorm 확산

2026년 3월 20일 20시 45분 (UTC), NPM에서 새로운 웜(CanisterWorm)으로 인한 다수의 패키지 감염 정황 발견
해당 악성코드는 공격자가 Trivy 공급망 공격을 통해 획득한 NPM 자격 증명 정보를 악용하여 배포한 것으로 추정
스스로 확산하는 악성코드가 C2 dead-drop*을 수행하기 위해 ICP Canister**를 C2로 이용하는 점에서 CanisterWorm으로 명명
영향 받은 패키지 : @EmilGroup 28개 패키지, @opengov 16개 패키지, @teale.io/eslint-config, @airtm/uuid-base32, @pypestream/floating-ui-dom 등 66개 이상 패키지
* Dead Drop : 공격자가 직접 통신하지 않고 기존의 정상 웹 서비스에 명령, 데이터 또는 C2 주소 정보를 게시하고 감염된 시스템에서 이를 조회하도록 하는 간접 전달 방식 ** ICP Canister : Internet Computer(ICP) 블록체인 상에서 실행되는 스마트 컨트랙트 실행 단위로 애플리케이션 코드와 상태 데이터를 함께 담아 실행 및 저장하는 배포 객체

4.1. NPM 패키지 악성코드(CanisterWorm) 상세 분석

감염된 패키지 중 22종의 패키지를 확보하여 4종의 index.js, 3종의 deploy.js, 1종의 service.py 악성코드 파일 분석
악성 npm 패키지 파일 구조
분석 파일 정보

1) index.js - Execution, Collection

지속성 확보 및 추가 작업을 위한 악성코드(service.py)를 설치하고 자동 확산을 위한 악성코드(deploy.js) 실행
확보한 index.js 파일 3종 중 2종의 경우 코드는 동일하나 작성된 주석의 내용이 상이하여 해시 값도 상이
초기 버전으로 추정되는 파일(MD5: 46e7a5c4cf645b77f24023eef873f56f)의 경우 지속성 확보 및 추가 작업을 위한 악성코드 설치 기능만 발견
동작 과정
1.
지속성 확보 및 추가 작업을 위한 악성코드 설치 및 실행
a.
하드코딩된 BASE64_PAYLOAD를 base64 디코딩하여 ~/.local/share/pgmon/service.py 파일로 저장
b.
user systemd 서비스 파일 생성 : ~/.config/systemd/user/pgmon.service
c.
pgmon.service 서비스 등록 및 실행
i.
systemctl --user daemon-reload
ii.
systemctl --user enable pgmon.service
iii.
systemctl --user start pgmon.service
2.
자동 확산을 위한 악성코드 실행
a.
NPM 토큰 수집
i.
.npmrc 파일 : ~/.npmrc, ./.npmrc, /etc/npmrc 에서 _authToken= 또는 :_authToken= 패턴 탐색하여 토큰 수집
ii.
환경 변수 : NPM_TOKEN, NPM_TOKENS 또는 NPMTOKEN이 모두 포함된 변수에서 토큰 수집
iii.
config : npm config get //registry.npmjs.org/:_authToken 에서 토큰 수집
b.
NPM 토큰 발견 시 deploy.js 실행
npm 토큰 탐색하여 존재 시 scripts/deploy.js가 있는지 확인하여 발견 시 백그라운드 detached 프로세스로 실행
수집한 토큰은 NPM_TOKENS 환경변수로 저장
index.js (MD5 : 55405de62427ac56106f0fdb1c33dedd) 내용
index.js (MD5 : 46e7a5c4cf645b77f24023eef873f56f) 내용

2) deploy.js - Lateral Movement

피해 시스템의 NPM 토큰을 탈취하여 해당 계정의 패키지에 악성코드를 심어 정상 패키지로 위장하여 배포하는 동작 수행
일반적인 deploy.js의 역할은 현재 내 패키지를 빌드하고 npm에 배포
동작 과정
1.
NPM 토큰 수집 후 해당 토큰의 계정 및 패키지 식별
a.
환경변수에서 NPM 토큰(NPM_TOKENS, NPM_TOKEN) 수집
b.
확보한 토큰의 계정명 식별 후 토큰 유효성 확인
https://registry.npmjs.org/-/whoami 엔드포인트에 Bearer 토큰 사용하여 요청
c.
해당 토큰의 계정이 maintainer로 등록된 패키지들을 250개 단위로 식별
2.
NPM 패키지 감염 및 확산 시도
a.
현재 로컬의 package.json, README.md 파일 백업
b.
식별해놓은 패키지의 README.md, package.json 파일을 악성 파일로 덮어쓴 후 현재 Release된 버전보다 x.x.1 높은 버전으로 변경하고 publish하여 Release 배포
c.
로컬 시스템의 파일을 전에 백업해두었던 package.json, README.md 파일로 복원하여 흔적 은폐
deploy.js (MD5 : 958c8f4f9145a7d67692db172f73c650) 내용
확보한 다른 샘플 2종도 동일한 기능을 수행하는 것으로 확인되나, 그 중 파일 1종(MD5: df43394b926e609e6ad020b157b151a1)의 경우 코드 구성이 상이
주석, 로깅, 에러 출력 등 운영 목적으로 작성된 코드가 다수 발견
주석과 구현이 일부 일치하지 않으며, 주석이 지나치게 상세하고, 로깅 기능 등에 각종 이모지가 사용된 점 등을 보아 LLM의 도움을 받아 작성한 코드로 추정
deploy.js (MD5: df43394b926e609e6ad020b157b151a1) 내용

3) service.py - Persistence

Trivy v0.69.4.에서 발견된 지속성 유지 및 추가 작업을 위해 사용하는 페이로드(sysmon.py, MD5 : b676c0703f8e4d6a198aa370ca4f5405)와 동일한 파일로 파일명만 상이
동작 과정
1.
최초 1회 300초(5분) 대기
2.
C2에 접속하여 응답 데이터를 읽어왔을 때 "http"로 시작하면 URL로 판단하여 그대로 반환, 아닐 경우 None 반환
C2(C_URL) : https://tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0[.]io/
해당 C2는 ICP Canister(tdtqy-oyaaa-aaaae-af2dq-cai)에 접근하는 주소로, 평소에는 정상 유튜브 링크를 작성하고 악성 페이로드 사용 시에 C2 도메인으로 교체하여 사용하는 것으로 추정
분석 시점 기준 해당 도메인은 접속 불가이며 VirusTotal 조회 시 발견된 시점에는 정상 유튜브 링크가 작성되었던 것으로 확인
3.
C2에서 읽어온 URL 주소가 이전에 접근한 주소와 다르고 URL 내에 “youtube.com”(킬 스위치 목적)이 들어가 있지 않은 경우에 동작 수행
전달받은 URL에서 파일 다운로드하여 TARGET(/tmp/pglog)에 저장 후 실행권한 755 부여하고 분리된 세션으로 실행
접근했던 URL은 STATE(/tmp/.pg_state)에 기록
4.
3000초(50분) 대기 후 과정 2~3 반복

05. Checkmarx/OpenVSX

TeamPCP는 탈취한 GitHub 개인 액세스 토큰(PAT)을 사용하여 Checkmarx에서 개발한 오픈 소스 인프라 코드 보안 스캐너인 KICS 공격
3월 23일 12:53 (UTC): Checkmarx의 OpenVSX* 확장 프로그램인 cx-dev-assist** 1.7.0 및 ast-results*** 2.53.0가 OpenVSX 계정을 통해 12초 간격으로 게시
3월 23일 12:58 ~ 16:50(UTC): KICS-github-action가 영향을 받은 것으로 확인되었으며 해당 저장소는 16:50(UTC)에 폐쇄
3월 23일 19:24(UTC): KICS-github-action 저장소가 복구되었으며 관리자는 문제가 해결되었다고 안내
3월 23일 22:25(UTC): Sysdig에서 ast-github-action(v2.3.28)도 영향을 받은 것으로 보고
3월 23일 22:35(UTC): Wiz에서 cx-dev-assist 1.7.0 및 ast-results 2.53.0이 손상된 점 확인
3월 24일 9:00(UTC): Checkmarx는 KICS GitHub 액션 및 OpenVSX 플러그인 관련 문제를 해결하는 보안 업데이트 발표
* OpenVSX : VS Code 계열 IDE에서 사용하는 확장 프로그램을 배포 및 설치할 수 있도록 하는 벤더 중립의 오픈 소스 플랫폼 ** cx-dev-assist : 개발자가 IDE에서 코드를 작성하는 동안 실시간 취약점 식별, 수정 가이드를 제공하는 개발자용 보안 보조 확장 프로그램 *** ast-results : Checkmarx One에서 수행한 보안 스캔 결과를 IDE로 불러와 취약점을 확인하고 조치할 수 있게 해주는 확장 프로그램

5.1. Checkmarx/OpenVSX 악성코드 분석 : kics-github-action, ast-github-action 상세분석

KICS-github-actionast-github-actionaction.yml 파일만 상이하고 핵심 동작을 수행하는 setup.sh 파일은 동일한 파일로 확인

1) action.yml - Execution

kics-github-actionast-github-action에서 발견된 악성 커밋 확인 시 action.yml에 “Prepare Environment” 라는 이름의 setup.sh 파일을 실행하는 작업 추가
kics-github-action action.yml 추가 내용
변경 내용
ast-github-action action.yml 추가 내용
변경 내용

2) setup.sh

setup.sh 파일은 Hosted runner 환경의 자격증명 및 민감정보 탈취 행위 수행
trivy-action의 entrypoint.sh 코드에서 C2Self Hosted Runner 환경에서 실행하는 Python Script만 다르고 동일한 동작을 수행하는 코드로 확인되어 상세 동작은 해당 내용 참고
C2 : checkmarx[.]zone
setup.sh (MD5: 0e12b77dc2ee0908b4d5827b6a4c00db) 내용

3-1) Github Hosted Runner Linux 기반 Python Script

setup.sh에서 Github Hosted Runner 환경인지 여부에 따라 다른 파이썬 스크립트 실행
Github Hosted Runner 환경에서 실행되는 페이로드(MD5: c77d1f7b23732cd8a958487ac92438e6)
Runner.Worker에 해당하는 /proc 발견 시 pid 정보 수집하여, 해당 pid의 /proc/{pid}/maps, /proc/{pid}/mem 접근
maps를 읽으면서 읽기 가능한 메모리 영역만 해당 영역의 시작-끝 주소를 mem에서 읽은 후 stdout으로 출력

3-2) Self Hosted Runner 기반 Python Script - TeamPCP Cloud Stealer

setup.sh에서 Github Hosted Runner 환경인지 여부에 따라 다른 파이썬 스크립트 실행
Github Hosted Runner가 아닌(Self Hosted Runner) 환경에서 실행되는 페이로드(MD5: b7a04d81eb2be05d1d4b8e05ec6b22c7)
trivy-action 악성코드에서 발견된 TeamPCP Cloud Stealer의 각종 자격 증명 정보 수집 기능피해자 시스템의 쿠버네티스 환경을 장악하여 지속성 확보하는 기능 추가
1.
각종 자격 증명 정보 수집
환경변수·SSH 키·클라우드 자격증명·Kubernetes 토큰·데이터베이스 비밀번호 등 각종 자격증명 탈취 수행
trivy-action 악성코드에서 발견된 TeamPCP Cloud Stealer 동작과 동일하여 세부 항목은 해당 내용 참고
2.
수집한 AWS 자격증명을 통한 추가 정보 수집
AWS 환경 변수 및 IMDSv2를 통해 확보한 IAM role 자격증명을 이용하여 Secrets Manager의 secret 목록 및 SSM Parameter Store의 파라미터 정보 조회 시도
3.
수집한 Kubernetes 자격증명을 통한 클러스터 정보 수집 및 각 노드에 지속성 확보를 통한 클러스터 내부 장악 시도
Kubernetes ServiceAccount(SA) 토큰을 이용한 클러스터 API 직접 조회 후 노드별 지속성 유지용 악성코드 드롭 시도 (클러스터 내부 확산)
토큰 경로와 CA 인증서를 읽고 Kubernetes API를 이용하여 Kubernetes 클러스터 직접 조회
Kubernetes Secret 및 네임스페이스별 Secret 조회
/api/v1/secrets, /api/v1/namespaces 조회 후 각 네임스페이스마다 /api/v1/namespaces/{ns}/secrets 재조회
Kubernetes Node를 조회하여 지속성 확보 작업 수행
각 노드마다 kube-system 네임스페이스에 새로운 Privileged Pod 생성
노드 호스트 파일시스템 직접 접근을 위해 privileged, hostPID, hostNetwork, hostPath("/") 설정
해당 Pod는 지속성 확보를 위한 drop_cmd 과정 수행
1.
호스트의 /root/.config/sysmon, /root/.config/systemd/user 디렉토리 생성
2.
하드코딩된 Base64 인코딩 데이터를 디코딩해서 호스트의 /root/.config/sysmon/sysmon.py로 저장
3.
sysmon.py에 실행권한 700 부여
4.
호스트 시스템 내에 python3 또는 python 경로 확인
5.
sysmon.py를 실행하는 /root/.config/systemd/user/sysmon.service 작성
6.
systemctl --user daemon-reload, systemctl enable --now sysmon.service 실행
현재 감염 호스트의 사용자 홈에도 동일한 sysmon.pysysmon.service를 생성하여 지속성 확보 시도
파일 설치 : ~/.config/sysmon/sysmon.py
systemd 유닛 : ~/.config/systemd/user/sysmon.service (서비스명: System Telemetry Service)

4) sysmon.py

지속성 유지 및 추가 작업을 위해 사용하는 페이로드
Trivy v0.69.4, NPM CansiterWorm에서 발견된 sysmon.py(service.py) 파일과 코드 구성 동일하여 상세 동작은 해당 내용 참조
사용된 C2가 ICP Canister에서 타이포스쿼팅이 적용된 C2(https://checkmarx[.]zone/raw)로 변경된 점만 상이

5.2. Checkmarx/OpenVSX 악성코드 분석 : OpenVSX 확장 프로그램 상세분석

1) environmentAuthChecker.js - Downloader

Checkmarx의 두 개의 손상된 확장 프로그램( ast-results v2.53.0및 cx-dev-assist v1.7.0)에 동일한 악성 페이로드(environmentAuthChecker.js) 포함
ast-results-2.53.0 내부 envrionmentAuthCheck.js 파일
cx-dev-assist-1.7.0 내부 environmentAuthChecker.js 파일
확장 프로그램 활성화 시 activateCore.js에서 악성 파일인 environmentAuthChecker.js실행하는 메커니즘
해당 페이로드는 피해자 시스템에서 하나 이상의 Github 또는 클라우드 제공업체(AWS, GCP, Azure)에 대한 자격 증명을 가지고 있는지 확인
자격 증명 확인 시 주요 Javascript 패키지 관리자인 npx, bunx, pnpx 또는 yarn dlx를 통해 C2(checkmarx[.]zone/static/checkmarx-util-1.0.4.tgz)에 추가 페이로드 다운로드
environmentAuthChecker.js 내용

2) index.js - Collection, Exfiltration

checkmarx-util-1.0.4에서 발견되는 악성 페이로드(index.js)는 TeamPCP Cloud Stealer 보다는 적은 범위의 각종 자격 증명 정보 탈취
수집 정보 : 환경변수/SSH/Git/AWS/Kubernetes/GCP/Azure/Docker/npm/Vault/DB/히스토리/VPN/지갑 정보
수집한 자격 증명 정보는 하이브리드 암호화를 통해 tpcp.tar.gz 파일로 암호화 후 C2( checkmarx[.]zone/vsx)로 유출
GITHUB_ACTIONS 환경변수가 없을 경우 지속성 유지 목적의 sysmon.js 파일 및 sysmon.service 서비스 생성 및 설정
파일 설치 : ~/.config/sysmon/sysmon.js (파일 확장자는 잘못 설정한 것으로 추정)
systemd 유닛 : ~/.config/systemd/user/sysmon.service (서비스명: System Telemetry Service)
index.js 내용

3) sysmon.js - Persistence

지속성 유지 및 추가 작업을 위해 사용하는 페이로드
동작 과정
1.
C2에 접속하여 읽어온 응답 데이터에 “youtube” 문자열 포함 시 이후 동작 생략
C2(C_URL) : https://checkmarx[.]zone/raw
평소에는 정상 유튜브 링크를 작성하여 숨어있다가 악성 페이로드 사용 시에 C2 도메인으로 교체하여 사용하는 것으로 추정
분석 시점 기준 해당 도메인은 접속 불가이며 VirusTotal 조회 시 발견된 시점에는 정상 유튜브 링크가 작성되었던 것으로 확인
2.
“youtube” 문자열 미포함 시 /tmp 폴더에 임시 파일 생성 후 해당 내용 작성
해당 파일에 실행권한 부여 후 subprocess.popen()으로 실행
3.
3000초(50분) 대기 후 과정 1~2 반복
sysmon.js 내용

06. LiteLLM PyPI 감염

(공격 개요)
LiteLLM은 오픈소스 Python 라이브러리로, OpenAI, Anthropic, Vertex AI, Bedrock 등 100여 개 이상의 LLM을 하나의 통합 인터페이스로 호출할 수 있게 해주는 프록시 게이트웨이
2026년 3월 24일, 공식 PyPI의 litellm==1.82.7, litellm==1.82.8 패키지에 악성 코드가 포함된 상태로 게시
v1.82.7은 10:39(UTC), v1.82.8은 10:52(UTC)에 게시됐고, 이후 PyPI가 약 40분 내 격리 조치를 적용했으며 LiteLLM 측은 16:00(UTC)까지 해당 버전 삭제 조치 진행
(사고 현황)
FutureSearch 측이 Cursor에서 MCP 플러그인을 시험하던 중 uvx가 최신 버전의 LiteLLM을 의존성으로 내려받아 로드하면서 이상 행위 발견되어 신고
최초 이상 징후는 Python 시작 직후 RAM 고갈과 대량의 Python 프로세스 생성으로 나타났으며, 이는 litellm_init.pth가 자식 Python 프로세스를 다시 호출하면서 발생한 비의도적 fork bomb 현상
공개 직후 신고 이슈가 봇 댓글로 도배되고 닫히는 교란 행위가 발생했으며 이후 LiteLLM 측은 관련 키 교체, Maintainer 계정 조치, 문제 버전 삭제 및 신규 릴리스 중단 조치 수행
(사고 원인)
LiteLLM 공식 조사 기준 이번 사고는 CI/CD 보안 스캔에 사용하던 Trivy 의존성과 연결된 것으로 보이며, 공격자가 노출된 자격증명으로 PyPI에 직접 악성 패키지를 게시한 것으로 추정
LiteLLM 측 후속 설명 기준 주요 배경 요인은 CircleCI 기반 공유 CI/CD 환경, 환경변수에 저장된 정적 PyPI·GHCR·Docker 자격증명, 그리고 버전이 고정되지 않은 Trivy 의존성으로 확인
(악성코드 특징)
악성 페이로드는 환경변수·SSH 키·클라우드 자격증명·Kubernetes 토큰·데이터베이스 비밀번호 등 각종 자격증명 탈취, 지속성 유지 및 Kubernetes 확산 기능까지 포함한 백도어
import 시 실행되도록 하는 조건(v1.82.7)에서 별도로 import 없이도 파이썬 실행 시 자동 실행되도록 하는 구조(v1.82.8)로 발전

6.1. LiteLLM PyPI 악성코드 상세 분석

1-1) proxy_server.py - Initial Access (LiteLLM v1.82.7)

LiteLLM v1.82.7의 litellm/proxy/proxy_server.py Line 128 ~ Line 139에 추가된 악성코드
다른 파일에서 litellm.proxy.proxy_server import 시 실행
추가된 악성 base64 인코딩 페이로드를 디코딩하여 p.py 파일로 작성 후 subprocess.run()을 이용하여 실행
proxy_server.py 정상 버전 (v1.82.6)
proxy_server.py 악성 버전 (v1.82.7)
proxy_server.py (Line 128 ~ Line 139) 내용

1-2) litellm_init.pth - Initial Access (LiteLLM v1.82.8)

LiteLLM v1.82.8에 추가 배포된 파일로, .pth 파일은 다른 파일에서 import 하는 등 명시적으로 사용하지 않더라도 Python 인터프리터 시작 시 site.py에 의해 자동으로 처리
base64 인코딩된 페이로드를 디코딩하여 p.py 파일로 작성 후 subprocess.run()을 이용해서 실행
해당 base64 페이로드는 proxy_server.py에서 발견되는 base64 페이로드와 동일
litellm_init.pth 내용

2) Base64 Payload - Execution, Exfiltration

proxy_server.py, litellm_init.pth 파일에서 base64 디코딩하여 실행하는 파이썬 스크립트
추가 페이로드(TeamPCP Cloud Stealer)를 실행하여 수집한 정보하이브리드 암호화를 적용하여 탈취
proxy_server.py에서 발견되는 base64 페이로드는 실제로 사용된 페이로드와 주석 처리된 2개의 페이로드 존재
실제로 사용된 base64 페이로드는 나머지 두 페이로드에서 사용하는 exec() 방식을 통한 추가 페이로드 실행에서 subprocess.run() 방식을 통한 실행으로 변경
주석 처리된 두 base64 페이로드는 서로 내부에서 사용한 B64_SCRIPT 값 외 나머지 코드 동일
데이터 임시 저장 파일로 “collected_vars.txt”를 사용
동작 과정
B64_SCRIPT 데이터(TeamPCP Cloud Stealer)를 디코딩하여 실행한 결과를 파일 c(collected)로 저장
openssl rand를 이용해 32바이트 랜덤 값(session.key) 생성
collected 데이터를 AES-256-CBC 방식으로 암호화하여 payload.enc 파일 생성
session.key 파일 내용을 PassPhrase로 사용해 PBKDF2 기반 AES 키, IV 파생하여 적용
session.key는 하드코딩된 공개키가 저장된 파일 p(public key)를 이용해 OAEP 패딩 모드의 RSA 암호화하여 session.key.enc 파일로 저장
본문 데이터는 AES-256-CBC 방식 암호화, 세션 키로 사용한 session.key 파일은 RSA-4096 공개키로 암호화하는 하이브리드 암호화
payload.enc, session.key.enc 파일을 압축하여 tpcp.tar.gz 파일 생성 후 C2(https://models.litellm[.]cloud/)로 전송하여 데이터 탈취
공식 사이트 : litellm.ai
proxy_server.py 내 첫 번째 base64 페이로드
proxy_server.py 내 주석 처리된 두 번째, 세 번째 base64 페이로드

3) TeamPCP Cloud Stealer - Collection, Lateral Movement

trivy-action 악성코드에서 발견된 TeamPCP Cloud Stealer의 각종 자격 증명 정보 수집 기능피해자 시스템의 쿠버네티스 환경을 장악하여 지속성 확보하는 기능 추가
Checkmarx kics-github-action, ast-github-action에서 발견되는 TeamPCP Cloud Stealer와 동일한 기능 수행하여 상세 동작은 해당 내용 참고
1.
각종 자격 증명 정보 수집
환경변수·SSH 키·클라우드 자격증명·Kubernetes 토큰·데이터베이스 비밀번호 등 각종 자격증명 탈취 수행
Trivy-Action 악성코드에서 발견된 TeamPCP Cloud Stealer 동작과 동일하여 해당 내용 참고
2.
수집한 AWS 자격증명을 통한 추가 정보 수집
AWS 환경 변수 및 IMDSv2를 통해 확보한 IAM role 자격증명을 이용하여 Secrets Manager의 secret 목록 및 SSM Parameter Store의 파라미터 정보 조회 시도
3.
수집한 Kubernetes 자격증명을 통한 클러스터 정보 수집 및 각 노드에 지속성 확보를 통한 클러스터 내부 장악 시도
Kubernetes ServiceAccount(SA) 토큰을 이용한 클러스터 API 직접 조회 후 노드별 지속성 유지용 악성코드 드롭 시도 (클러스터 내부 확산)
토큰 경로와 CA 인증서를 읽고 Kubernetes API를 이용하여 Kubernetes 클러스터 직접 조회
Kubernetes Secret 및 네임스페이스별 Secret 조회
/api/v1/secrets, /api/v1/namespaces 조회 후 각 네임스페이스마다 /api/v1/namespaces/{ns}/secrets 재조회
Kubernetes Node를 조회하여 지속성 확보 작업 수행
각 노드마다 kube-system 네임스페이스에 새로운 Privileged Pod 생성
노드 호스트 파일시스템 직접 접근을 위해 privileged, hostPID, hostNetwork, hostPath("/") 설정
해당 Pod는 지속성 확보를 위한 drop_cmd 과정 수행
1.
호스트의 /root/.config/sysmon, /root/.config/systemd/user 디렉토리 생성
2.
PERSIST_B64에 저장된 Base64 인코딩 데이터를 디코딩해서 호스트의 /root/.config/sysmon/sysmon.py로 저장
3.
sysmon.py에 실행권한 700 부여
4.
호스트 시스템 내에 python3 또는 python 경로 확인
5.
sysmon.py를 실행하는 /root/.config/systemd/user/sysmon.service 작성
6.
systemctl --user daemon-reload, systemctl enable --now sysmon.service 실행
현재 감염 호스트의 사용자 홈에도 동일한 sysmon.pysysmon.service를 생성하여 지속성 확보 시도
파일 설치 : ~/.config/sysmon/sysmon.py
systemd 유닛 : ~/.config/systemd/user/sysmon.service (서비스명: System Telemetry Service)

4) sysmon.py - Persistence

지속성 유지 및 추가 작업을 위해 사용하는 페이로드
LiteLLM proxy_server.py에서 주석 처리된 base64 페이로드의 진행 과정 상에서 발견되는 sysmon.py는 Hex 값을 RC4 암호화(Key: “nigger”)하여 해당 샘플과 동일한 base64 페이로드 생성
Trivy v0.69.4, NPM CansiterWorm에서 발견된 sysmon.py(service.py) 파일과 코드 구성 동일하여 상세 동작은 해당 내용 참조
사용된 C2가 ICP Canister에서 타이포스쿼팅이 적용된 C2(https://checkmarx[.]zone/raw)로 변경된 점만 상이

07. Telnyx PyPI 감염

(공격 개요)
Telnyx는 음성 통화, 메시징, 전화번호, 영상 등 실시간 통신 기능을 API 형태로 제공하는 클라우드 통신 플랫폼
2026년 3월 27일 03시 51분 28초(UTC), 악성코드가 포함된 Telnyx Python SDK의 무단 버전 두 개(4.87.14.87.2)가 PyPI에 게시, 같은 날 10시 13분(UTC)에 격리 조치
파이썬 패키지만 손상되었으며, 인프라, 네트워킹, 서비스 및 기타 API는 침해되지 않은 것으로 알려짐
악성코드는 telnyx/_client.py에 삽입되었으며, 모든 실행 경로가 모듈 범위에서 실행되도록 설정되어 있어 import telnyx를 통해 악성코드 실행 가능
Telnyx 공격 흐름도 (출처 : OX Security)

7.1. Telnyx PyPI 악성코드 상세 분석

1) _client.py

Telnyx v4.87.1, v4.87.2의 _client.py 파일의 코드는 동일하며 setup() 함수 호출 시 대소문자 표기가 달라서 해시 값이 상이
동작
운영체제 환경에 따라 다른 동작 수행
1.
Windows : setup() 함수 실행
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\msbuild.exe 파일 존재 확인하여 있을 경우 종료
현재 시간이 msbuild.exe.lock 파일의 수정 시간으로 부터 43,200초(12시간) 미만일 경우 종료
해당 시간 이상일 경우 msbuild.exe.lock 파일에 현재 시간 기록
해당 파일 숨김 속성(attrib +h) 설정
C2(https://83.142.209[.]203:8080/hangup.wav) 접근하여 파일 읽어와서 msbuild.exe.tmp 파일로 저장
읽어온 wav 파일에서 오디오 데이터 영역의 데이터를 읽어와 base64 디코딩 후 첫 8바이트는 Key로 사용하고 나머지 데이터를 XOR 복호화 하여 msbuild.exe 생성 후 CREATE_NO_WINDOW 플래그(0x08000000)와 함께 실행
2.
Linux, macOS : FetchAudio() 함수 실행
_client.py line 459에 삽입된 base64 인코딩 페이로드(_p)를 디코딩하여 실행
_clinet.py line 459에 삽입된 base64 인코딩 페이로드 일부
_client.py 내용 일부

2-1) Windows 환경 : msbuild.exe - RAT

분석 시점에는 해당 C2에 접근할 수 없어 wav 파일을 확인하지는 못하였으나 알려진 해시값을 통해 msbuild.exe 파일 확보
해당 실행 파일은 탐지를 피하기 위해 여러 난독화 및 회피 기법을 사용하는 로더
DJB2 해시 기반 API 해석, 시스템 콜 사용, Windows 이벤트 추적(ETW) 종료
DJB2 해시 기반 API 로드
EtwEventWrite 호출
exe 내부에 삽입된 PNG 파일에서 값을 추출하여 조합한 쉘코드를 dllhost.exe에 삽입하여 실행
dllhost.exe 실행 및 PNG 데이터 로드
exe 내부에 포함된 PNG 파일
Akamai에 의하면 해당 쉘코드는 RAT 백도어 역할을 수행하는 것으로 확인되며 수집한 데이터는 C2(checkmarx[.]zone/telemetry/checkmarx.json)로 전송하는 것으로 추정
하드코딩된 RC4 Key를 사용하여 내장된 구성 파일을 복호화하여 사용
RC4 Key : 33 1a b9 c0 32 cf 95 c8 9d 87 7e e0 5b 46 f8 d8
복호화된 구성 파일 내용
확인된 기능
명령어
동작
0x12
파일 읽기
0x17
프로세스 종료
0x18
레지스트리 읽기
0x2A
프로세스 생성
0x2B
암호화 및 데이터 유출
0x47
파이프를 통한 쉘 실행

2-2) Linux, macOS 환경 : FetchAudio()에서 실행하는 Python Script

Trivy-action의 entrypoint.sh 파일과 유사하게 추가 페이로드를 실행하고 해당 결과를 수집한 파일을 하이브리드 암호화하여 tpcp.tar.gz 파일로 압축 후 C2로 전송하는 동작 수행
추가 페이로드 실행 시 하드코딩된 base64 페이로드를 디코딩해서 실행하던 방식에서, C2를 통해 페이로드를 받아서 실행하는 방식으로 변환
C2로 사용된 IP(83.142.209[.]203)는 checkmarx[.]zone 하고 연결되었던 IP로 확인
동작 과정
C2(http://83.142.209[.]203:8080/ringtone.wav) 접근해서 temp.wav 파일로 다운로드
temp.wav 파일을 base64 디코딩 후 첫 8바이트를 Key로 하여 나머지 데이터를 XOR 복호화한 데이터를 실행하여 실행 결과를 collected(c)에 저장
데이터 수집 성공 시 하이브리드 암호화(AES-256-CBC + RSA-4096 OAEP) 적용하여 수집 데이터, 세션키 암호화 데이터를 tpcp.tar.gz 파일로 압축 후 C2(http://83.142.209[.]203:8080/)에 전송
FetchAudio python 스크립트

08. IoC, Indicator of Compromise

NO
Type
DATA
Info
1
MD5 SHA256
805c08686e755c063a0bb460bdf9dcc4 822dd269ec10459572dfaaefe163dae693c344249a0161953f0d5cdd110bd2a0
trivy v0.69.4 linux 64bit
2
MD5 SHA256
8bddcad83361397840fdb1ee97d8a6a6 f7084b0229dce605ccc5506b14acd4d954a496da4b6134a294844ca8d601970d
trivy v0.69.4 linux 32bit
3
MD5 SHA256
818271154971537a9b52e908b1463508 46975e946d77485a9d43434b73b112e95183e331962b0dafc371f05a1ffbbb16
(trivy v0.69.4) Github Hosted Runner 환경 메모리 정보 추출 파이썬 스크립트
4
MD5 SHA256
d761a6a7ae9f2254bd81ac234033a8b8 18a24f83e807479438dcab7a1804c51a00dafc1d526698a66e0640d1e5dd671a
(trivy-action) entrypoint.sh
5
MD5 SHA256
9f6075c462ca52dc56e5fce10328ac3b 83d7ad6f3ff22a6e0e021fa4541a23cdecac1ad4d0d4b018a7b7e92292cc8ccc
(trivy-action, setup-trivy) Self Hosted Runner 환경 TeamPCP Cloud Stealer
6
MD5 SHA256
c77d1f7b23732cd8a958487ac92438e6 d8c45b34ed3637c2a57ab532155c2e3933308b2e3ee6a977ef427f9078b843cd
(trivy-action, setup-trivy, ast-github-action) Github Hosted Runner 환경 메모리 정보 추출 파이썬 스크립트
7
MD5 SHA256
1d39656cc34bb9ef36f4992fd774f5b7 ef8a2c83882852c92d01a7356ca7a362aef98d1eae332ab48f993ea0ef3d8fe0
(setup-trivy) action.yaml
8
MD5 SHA256
f5560871f6002982a6a2cc0b3ee739f7 a0d229be8efcb2f9135e2ad55ba275b76ddcfeb55fa4370e0a522a5bdee0120b
(LiteLLM) proxy_server.py
9
MD5 SHA256
cde4951bee7e28ac8a29d33d34a41ae5 71e35aef03099cd1f2d6446734273025a163597de93912df321ef118bf135238
(LiteLLM) litellm_init.pth
10
MD5 SHA256
7cac57b2d328bd814009772dd1eda429 d6fc0ff06978742a2ef789304bcdbe69a731693ad066a457db0878279830d6a9
(LiteLLM) base64_payload_1_decoded
11
MD5 SHA256
0f0223eb0c5254769fc7fe9ae3d26e3f 472f6cd3e735a347aeda0f05ac6cb3d59069ce3cae119f97d0c4a758a4cf1ae7
(LiteLLM) base64_payload_2_decoded
12
MD5 SHA256
ae60726d04bc06d0c623e567e8e9b241 8eaf4c4d0b82620bcda29b97896e2da0a754205c035721479f7ceafb817e4466
(LiteLLM) base64_payload_3_decoded
13
MD5 SHA256
6c9da8de6797d4a446d962d5f3f0c22c ce681356c8870af8583ed753fff330e2897f4629c45677f8065649a47b20a111
(LiteLLM) TeamPCP Cloud Stealer
14
MD5 SHA256
30808ef5a07e62d46e7ba6a82d9e3e9e a5dd088bc7daa4253fc44a99f8f8008b4f16ae04f345354f455e751fdc90a9a4
(LiteLLM) TeamPCP Cloud Stealer
15
MD5 SHA256
0a487dcd6ef8f98d7fcee0583592a89b 0f6223cd6c875b31e64f8d2b9e8798a82e972c9ab14553a812ebb0d5094c5d91
(LiteLLM) TeamPCP Cloud Stealer
16
MD5 SHA256
8ca60ad84b6f6b3b9352e77cd8682d81 6cf223aea68b0e8031ff68251e30b6017a0513fe152e235c26f248ba1e15c92a
(LiteLLM) sysmon.py
17
MD5 SHA256
ae4c00eca1bb6083855deb4281c4d1bd c0ca84eaa706d25465711f0f66c7b5d897e219ae239041c5419583291ab752cd
(kics-github-action) action.yml
18
MD5 SHA256
e5ac316962931b524227aa20491d24dd 72dab34c6b995cc63314eb95c9a2e2316ddfe10c3dc6d1029c7658fa677fb59f
(ast-github-action) action.yml
19
MD5 SHA256
0e12b77dc2ee0908b4d5827b6a4c00db 15ccf5d10f23dd6b69574d21c2ba516fd3d0dbf9fa597a02338f41c3b95d78aa
(kics-github-action, ast-github-action) setup.sh
20
MD5 SHA256
b7a04d81eb2be05d1d4b8e05ec6b22c7 eb6fde7c1ff4c275b5ec11e604c20593d8855eeae3be2d83bbe859a1487548cf
(kics-github-action, ast-github-action) TeamPCP Cloud Stealer
21
MD5 SHA256
767f50799df6aef4f2cb121ba7c01ad2 42246762d83296f47f608f34ea8e966e1b71212948e4156dea1619d01accb52d
(kics-github-action, ast-github-action) sysmon.py
22
MD5 SHA256
81bfd2c98536a306357a54746d2b3d07 65bd72fcddaf938cefdf55b3323ad29f649a65d4ddd6aea09afa974dfc7f105d
(OpenVSX) ast-results-2.53.0.vsix
23
MD5 SHA256
60fe39ec4452813f849bde618e3b5963 744c9d61b66bcd2bb5474d9afeee6c00bb7e0cd32535781da188b80eb59383e0
(OpenVSX) cx-dev-assist-1.7.0.vsix
24
MD5 SHA256
49e06269c77e9f028aef505f2c92d5a6 527f795a201a6bc114394c4cfd1c74dce97381989f51a4661aafbc93a4439e90
(OpenVSX) environmentAuthChecker.js
25
MD5 SHA256
0fccc8e3a03896f45726203074ae225d 0d66d8c7e02574ff0d3443de0585af19c903d12466d88573ed82ec788655975c
(OpenVSX) checkmarx-util-1.0.4.tgz
26
MD5 SHA256
05bacbe163ef0393c2416cbd05e45e74 cd6af6c9ba149673ff89a1f1ccc8ec40a265a3b54ad455fbef28dc2967a98e45
(OpenVSX) index.js
27
MD5 SHA256
8d317fb5e199aed37bf87a4ebc630b49 2c89570dc5e4b7ce816e2d59e552ae146b59a5c4664b0ba502f98ce4354e1af
(OpenVSX) sysmon.js
28
MD5 SHA256
188d8592f393ce45f7273102f02efee1 7321caa303fe96ded0492c747d2f353c4f7d17185656fe292ab0a59e2bd0b8d9
telnyx 4.87.1-py3-none-any.whl
29
MD5 SHA256
5870a0bf82bbdf2687d8dce89dfa668f cd08115806662469bbedec4b03f8427b97c8a4b3bc1442dc18b72b4e19395fe3
telnyx 4.87.2-py3-none-any.whl
30
MD5 SHA256
b1c6036b046bcf8c80601742ebcc61b0 23b1ec58649170650110ecad96e5a9490d98146e105226a16d898fbe108139e5
(Telnyx v4.87.1) _client.py
31
MD5 SHA256
9e837f0b9e8037b06256e2ec4291f757 ab4c4aebb52027bf3d2f6b2dcef593a1a2cff415774ea4711f7d6e0aa1451d4e
(Telnyx v4.87.2) _client.py
32
MD5 SHA256
599a186de45023bddfb37ba52d69dbf5 84edce66f09c55bbb44754411bde4b092288d172734df62fac20d6f794b3a2ec
(Telnyx) FetchAudio 파이썬 스크립트
33
MD5 SHA256
d528effabbd9cd66aaa11bc8777bb110 7290353a3bc2b18e9ea574d3294b09e28edaa6b038285bb101cf09760f187dcd
(Telnyx) msbuild.exe
34
MD5 SHA256
217e86944372006f89b405b33d905884 dafc1cc5d39bc303562d8587b698b6351e843b77c01764efa8b423a36b88fa6d
(Telnyx) msbuild.exe 내 dll
35
MD5 SHA256
99ec27d6392b0fab6a7d88ac03e5c509 3e4216020945f1cd18beab71ea1a791d0d41f8c3b0ca038e27566c60bdfbd4ad
(NPM Package) react-leaflet-marker-layer(0.1.5)
36
MD5 SHA256
55a13227870b02e4c5b971d151152e45 4e1a2647daa6db51cda32247df0652fd03c903738235cdecd55ccc161ce50fdc
(NPM Package) @emilgroup/commission-sdk(1.0.2)
37
MD5 SHA256
9b0e66253bcdb92e8097148d60346a79 8b21b3f6b3e8a26cfc40cd96e91536ecfc49aba79b9ccac1f995dfc5a82c7ab6
(NPM Package) @emilgroup/customer-sdk(1.54.5)
38
MD5 SHA256
a4c3cf93cbdfc705ab2814a6360ed838 9d6c0f606af8b3ea56e2e6d795d07d32394b2d9a58f364559ee68403ab11997f
(NPM Package) @emilgroup/discount-sdk(1.5.3)
39
MD5 SHA256
9d7e17018d4a41f3aa0a2d45862bea1f 9f8249c4ff2a0453cf5a9a436030b9f47ecb458d98558b04103ef8f5554fea28
(NPM Package) opengov-k6-core(1.0.2)
40
MD5 SHA256
b9d0641e713ce18c3e6bb238b680d4a2 27e8c218d0606fcd7be1db3e9334502ebf524082e110e27ab56de3b597f67e60
(NPM Package) cit-playwright-test(1.0.1)
41
MD5 SHA256
c859e1b2ef0cba30bbd3587f4badb598 45e3e0afb0d04f4cf3680394b42e28ee0fe3c5d6da478a065dc38d964198da23
(NPM Package) @opengov/ppf-eslint-config(0.1.11)
42
MD5 SHA256
e00c35e16eefd0db81a7f137a91a6186 46b0ede453a217493b5792faa70627aeeaf0d3736af864a9907a1b89455088ed
(NPM Package) @emilgroup/task-sdk(1.0.2)
43
MD5 SHA256
564378ffd59bb29710e0fe83b068e373 53cc8a09e3f929fce84f097e69392b22e35de08d3a895bbc85caaad1e755371d
(NPM Package) babel-plugin-react-pure-component(0.1.6)
44
MD5 SHA256
85f371c9bf10c972ae899887262fea3a 53cfde5d7756a21b92d9b5d078aad50a6555547d916980c197ee0277d15b94eb
(NPM Package) @emilgroup/setting-sdk(0.2.3)
45
MD5 SHA256
b18637344312319dad79c67079a29a4d 73a80f59a5ec9628d47ad94dcbe70e8e68db41fa67fd8974938baf032dede790
(NPM Package) @teale.io/eslint-config(1.8.10)
46
MD5 SHA256
a3aabfd9386758135fdc811b0d143781 379a45b1ddef1cf0bdea1ec39aa4478e2e10e2ca00dfa33306a08ca7231b649e
(NPM Package) react-leaflet-cluster-layer(0.0.4)
47
MD5 SHA256
ec65d120a9a5309d451718f847afa830 707cf3d720c60cc1786f4a69c02e8f43883036d3c2a1fd89c89fa77e9a1d2283
(NPM Package) react-autolink-text(2.0.1)
48
MD5 SHA256
370d7f3e136027746975c3e614853fb5 767fc3f1087b7946aa9694fcb7da60d0aae5237a0277f3b298cbab7643edef98
(NPM Package) react-leaflet-heatmap-layer(2.0.1)
49
MD5 SHA256
29e170d737dcaf88435847aa4eecf553 a7d9c27d3be05c6fa0416573f3bda062b91ddc74fff7f7960b3c3f7885b61434
(NPM Package) @leafnoise/mirage(2.0.3)
50
MD5 SHA256
daa82da235b97b194a9e7efcb0d4580e a79a16460a419fc2f1c3f8989e9267115cf9249663517f076442f370b8b80276
(NPM Package) @opengov/ppf-backend-types(1.141.2)
51
MD5 SHA256
27d8dfa079016f1181e5eef2c66157d6 a4842b7956b217ddf955cdd860032517b79fbbe4dd9215dd783847a45da2fff1
(NPM Package) @opengov/form-utils(0.7.2)
52
MD5 SHA256
4d6a1c841d772412a3a0bb595e602c82 b7d2a540e591492a71fa7921fdb692187d62ffe44e341114ad58105db6cf6d8b
(NPM Package) @opengov/qa-record-types-api(1.0.3)
53
MD5 SHA256
b8b39afa3996040449acbc49baf9864b d8961f91d6f51b5552b9ef8b0001d907fc3663dfc918d7d528aaca166920cecf
(NPM Package) @emilgroup/document-sdk-node(1.43.6)
54
MD5 SHA256
09ead57d2a07cf30ceab89065019f689 f23fcc3045f63d526dfa5d65f1203e5f61812e940c02654d2d22520ceb028fcb
(NPM Package) @airtm/uuid-base32(1.0.2)
55
MD5 SHA256
8e27a6be443fd1ab37c9f1c1ec3fef14 f101f3b8780afa75f8023fb10a0d5a30b9f51c1141e91a8799d12c4dfa3d5a47
(NPM Package) @teale.io/eslint-config(1.8.13)
56
MD5 SHA256
4f26a6a3375ff139ddf6b8fc93a50a53 fcdda01cd9233d775b417605c53ebad71afada9f1b616c627c3e7a147a5b1c67
(NPM Package) @opengov/form-renderer(0.2.20)
57
MD5 SHA256
55405de62427ac56106f0fdb1c33dedd c37c0ae9641d2e5329fcdee847a756bf1140fdb7f0b7c78a40fdc39055e7d926
(NPM CanisterWorm) index.js
58
MD5 SHA256
986a8af4d0b5ea68e1949de5fefdfbf2 f564bbdb350cf5a0894023795049708b01cbe76781a5e695f52e56b762955431
(NPM CanisterWorm) index.js
59
MD5 SHA256
46e7a5c4cf645b77f24023eef873f56f 61ff00a81b19624adaad425b9129ba2f312f4ab76fb5ddc2c628a5037d31a4ba
(NPM CanisterWorm) index.js
60
MD5 SHA256
8cf49650b7a000d09e8af77c314dfdad 0c0d206d5e68c0cf64d57ffa8bc5b1dad54f2dda52f24e96e02e237498cb9c3a
(NPM CanisterWorm) index.js
61
MD5 SHA256
958c8f4f9145a7d67692db172f73c650 158091ec92a3a91d7d2d29e6b867d47479d624bcae5f067cc80af4eff91c9729
(NPM CanisterWorm) deploy.js
62
MD5 SHA256
8bfefb76454efe404359831d4fe7137c 5e2ba7c4c53fa6e0cef58011acdd50682cf83fb7b989712d2fcf1b5173bad956
(NPM CanisterWorm) deploy.js
63
MD5 SHA256
df43394b926e609e6ad020b157b151a1 7df6cef7ab9aae2ea08f2f872f6456b5d51d896ddda907a238cd6668ccdc4bb7
(NPM CanisterWorm) deploy.js
64
MD5 SHA256
b676c0703f8e4d6a198aa370ca4f5405 b219ce2263c913655269946b884c38ee3dc577a7f1221d4524f2b2bceb1f55ad
(NPM CanisterWorm) service.py(sysmon.py)
65
Domain
https://socketusercontent[.]com/blob/QGKJPg-gHR5Q43Kt6GATFGgDa_B1SZpimbgZA0eXdZxo/
66
Domain
https://scan.aquasecurtiy[.]org
67
Domain
https://models.litellm[.]cloud/
68
Domain
https://checkmarx[.]zone/raw
69
Domain
https://tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0[.]io/
70
Domain
http://83.142.209[.]203:8080/hangup.wav
Telnyx msbuild.exe 다운로드
71
Domain
http://83.142.209[.]203:8080/ringtone.wav
Telnyx fetchaudio에서 접근
72
Domain
http://83.142.209[.]203:8080/
Telnyx 정보 탈취 C2
73
IP
46.151.182.203
74
IP
83.142.209.11
75
IP
45.148.10.212
76
RSA Public Key
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvahaZDo8mucujrT15ry+ 08qNLwm3kxzFSMj84M16lmIEeQA8u1X8DGK0EmNg7m3J6C3KzFeIzvz0UTgSq6cV pQWpiuQa+UjTkWmC8RDDXO8G/opLGQnuQVvgsZWuT31j/Qop6rtocYsayGzCFrMV 2/ElW1UE20tZWY+5jXonnMdWBmYwzYb5iwymbLtekGEydyLalNzGAPxZgAxgkbSE mSHLau61fChgT9MlnPhCtdXkQRMrI3kZZ4MDPuEEJTSqLr+D3ngr3237G14SRRQB IqIjly5OoFkqJxeNPSGJlt3Ino0qO7fy7LO0Tp9bFvXTOI5c+1lhgo0lScAu1ucA b6Hua+xRQ6s//PzdMgWT3R1aK+TqMHJZTZa8HY0KaiFeVQ3YitWuiZ3ilwCtwhT5 TlS9cBYph8U2Ek4K20qmp1dbFmxm3kS1yQg8MmrBRxOYyjSTQtveSeIlxrbpJhaU Z7eneYC4G/Wl3raZfFwoHtmpFXDxA7HaBUArznP55LD/rZd6gq7lTDrSy5uMXbVt 6ZnKd0IwHbLkYlX0oLeCNF6YOGhgyX9JsgrBxT0eHeGRqOzEZ7rCfCavDISbR5xK J4VRwlUSVsQ8UXt6zIHqg4CKbrVB+WMsRo/FWu6RtcQHdmGPngy+Nvg5USAVljyk rn3JMF0xZyXNRpQ/fZZxl40CAwEAAQ==
Trivy, CanisterWorm, LiteLLM, Telnyx 악성코드에서 공통으로 발견된 RSA공개키

09. 참고자료

[별첨] Trivy 공급망 공격 영향 대상 목록

Type
Name
Affected versions
Python package
litellm
1.82.7, 1.82.8
Python package
telnyx
4.87.1, 4.87.2
Docker image
aquasec/trivy
0.69.4, 0.69.5, 0.69.6
Docker image
ghcr.io/aquasecurity/trivy
0.69.4, 0.69.5, 0.69.6
Docker image
docker.io/aquasec/trivy:0.69.4
0.69.4, 0.69.5, 0.69.6
Docker image
public.ecr.aws/aquasecurity/trivy
0.69.4, 0.69.5, 0.69.6
GitHub action
aquasecurity/setup-trivy
0.2.0 to 0.2.6
GitHub action
aquasecurity/trivy-action
All tags not starting with v, except 0.35.0
GitHub action
Checkmarx/kics-github-action
v1.1
GitHub action
Checkmarx/ast-github-action
v2.3.28
OpenVSX extension
ast-results
2.53.0
OpenVSX extension
cx-dev-assist
1.7.0
npm package
@pypestream/floating-ui-dom
2.15.1
npm package
@leafnoise/mirage
2.0.3
npm package
@opengov/ppf-backend-types
1.141.2
npm package
eslint-config-ppf
0.128.2
npm package
react-leaflet-marker-layer
0.1.5
npm package
react-leaflet-cluster-layer
0.0.4
npm package
react-autolink-text
2.0.1
npm package
opengov-k6-core
1.0.2
npm package
jest-preset-ppf
0.0.2
npm package
cit-playwright-tests
1.0.1
npm package
eslint-config-service-users
0.0.3
npm package
babel-plugin-react-pure-component
0.1.6
npm package
@opengov/form-renderer
0.2.20
npm package
@opengov/qa-record-types-api
1.0.3
npm package
@opengov/form-builder
0.12.3
npm package
@opengov/ppf-eslint-config
0.1.11
npm package
@opengov/form-utils
0.7.2
npm package
react-leaflet-heatmap-layer
2.0.1
npm package
@virtahealth/substrate-root
1.0.1
npm package
@airtm/uuid-base32
1.0.2
npm package
@emilgroup/setting-sdk
0.2.3,0.2.2,0.2.1
npm package
@emilgroup/partner-portal-sdk
1.1.3,1.1.2,1.1.1
npm package
@emilgroup/gdv-sdk-node
2.6.3,2.6.2,2.6.1
npm package
@emilgroup/docxtemplater-util
1.1.4,1.1.3,1.1.2
npm package
@emilgroup/accounting-sdk
1.27.3,1.27.2,1.27.1
npm package
@emilgroup/task-sdk
1.0.4,1.0.3,1.0.2
npm package
@emilgroup/setting-sdk-node
0.2.3,0.2.2,0.2.1
npm package
@emilgroup/task-sdk-node
1.0.4,1.0.3,1.0.2
npm package
@emilgroup/partner-sdk
1.19.3,1.19.2,1.19.1
npm package
@emilgroup/numbergenerator-sdk-node
1.3.3,1.3.2,1.3.1
npm package
@emilgroup/customer-sdk
1.54.5,1.54.4,1.54.3,1.54.2,1.54.1
npm package
@emilgroup/commission-sdk
1.0.3,1.0.2,1.0.1
npm package
@emilgroup/process-manager-sdk
1.4.2,1.4.1
npm package
@emilgroup/changelog-sdk-node
1.0.3,1.0.2
npm package
@emilgroup/document-sdk-node
1.43.6,1.43.5,1.43.4,1.43.3,1.43.2,1.43.1
npm package
@emilgroup/commission-sdk-node
1.0.3,1.0.2,1.0.1
npm package
@emilgroup/document-uploader
0.0.12,0.0.11,0.0.10
npm package
@emilgroup/discount-sdk
1.5.3,1.5.2,1.5.1
npm package
@emilgroup/discount-sdk-node
1.5.2,1.5.1
npm package
@teale.io/eslint-config
1.8.16,1.8.15,1.8.14,1.8.13,1.8.12,1.8.11,1.8.10,1.8.9
npm package
@emilgroup/insurance-sdk
1.97.6,1.97.5,1.97.4,1.97.3,1.97.2,1.97.1
npm package
@emilgroup/account-sdk
1.41.2,1.41.1
npm package
@emilgroup/account-sdk-node
1.40.2,1.40.1
npm package
@emilgroup/accounting-sdk-node
1.26.2,1.26.1
npm package
@emilgroup/api-documentation
1.19.2,1.19.1
npm package
@emilgroup/auth-sdk
1.25.2,1.25.1
npm package
@emilgroup/auth-sdk-node
1.21.2,1.21.1
npm package
@emilgroup/billing-sdk
1.56.2,1.56.1
npm package
@emilgroup/billing-sdk-node
1.57.2,1.57.1
npm package
@emilgroup/claim-sdk
1.41.2,1.41.1
npm package
@emilgroup/claim-sdk-node
1.39.2,1.39.1
npm package
@emilgroup/customer-sdk-node
1.55.2,1.55.1
npm package
@emilgroup/document-sdk
1.45.2,1.45.1
npm package
@emilgroup/gdv-sdk
2.6.2,2.6.1
npm package
@emilgroup/insurance-sdk-node
1.95.2,1.95.1
npm package
@emilgroup/notification-sdk-node
1.4.2,1.4.1
npm package
@emilgroup/partner-portal-sdk-node
1.1.2,1.1.1
npm package
@emilgroup/partner-sdk-node
1.19.2,1.19.1
npm package
@emilgroup/payment-sdk
1.15.2,1.15.1
npm package
@emilgroup/payment-sdk-node
1.23.2,1.23.1
npm package
@emilgroup/process-manager-sdk-node
1.13.2,1.13.1
npm package
@emilgroup/public-api-sdk
1.33.2,1.33.1
npm package
@emilgroup/public-api-sdk-node
1.35.2,1.35.1
npm package
@emilgroup/tenant-sdk
1.34.2,1.34.1
npm package
@emilgroup/tenant-sdk-node
1.33.2,1.33.1
npm package
@emilgroup/translation-sdk-node
1.1.2,1.1.1
IGLOO Corp. 2026. All rights reserved.