메뉴
HN
Hacker News 30일 전

PyTorch Lightning 라이브러리서 '듄' 테마 악성코드 발견

IMP
9/10
핵심 요약

인기 딥러닝 프레임워크인 PyPI 패키지 'lightning'의 2.6.2 및 2.6.3 버전에 공급망 공격(Supply Chain Attack)이 발생했습니다. 악성코드는 모듈 임포트 시 자동으로 실행되어 클라우드 자격 증명 및 토큰을 탈취하고 npm 생태계로까지 확산됩니다. 관련 패키지를 사용 중이라면 즉시 버전을 점검하고 키(Key)를 교체해야 합니다.

번역된 본문

널리 사용되는 딥러닝 프레임워크인 PyPI 패키지 'lightning'이 2026년 4월 30일에 게시된 2.6.2 및 2.6.3 버전에 영향을 미치는 공급망 공격(Supply Chain Attack)에 노출되었습니다. 이미지 분류기 구축, LLM 미세 조정, 디퓨전 모델(Diffusion model) 실행 또는 시계열 예측 모델 개발 팀은 종종 의존성 트리(Dependency tree)에 lightning을 포함하고 있습니다. pip install lightning을 실행하는 것만으로도 악성코드가 활성화됩니다.

악성 버전에는 모듈 가져오기(Import) 시 자동으로 실행되는 난독화된 JavaScript 페이로드(Payload)가 숨겨진 _runtime 디렉토리를 포함하고 있습니다. 이 공격은 자격 증명, 인증 토큰, 환경 변수 및 클라우드 비밀(Cloud secrets)을 탈취할 뿐만 아니라 GitHub 리포지토리를 감염시키려 시도합니다. 영화 '듄(Dune)'의 새다카(Hulud, 모래벌레)를 테마로 삼고 있으며, EveryBoiWeBuildIsaWormBoi라는 이름의 퍼블릭 리포지토리를 생성하는 특징이 있습니다. 우리는 이 공격이 과거 'mini Shai-Hulud' 캠페인 배후의 위협 행위자(Threat actor)가 저지른 것으로 보고 있습니다. IOC(침해 지표) 구조가 해당 작전과 일치합니다. 악성 커밋 메시지가 동일한 '듄' 테마의 명명 규칙을 따르며, 이번 캠페인에서는 기존의 Mini Shai-Hulud 공격과 구별하기 위해 EveryBoiWeBuildIsAWormyBoi라는 접두사를 사용합니다.

영향을 받는 패키지

  • lightning 버전 2.6.2
  • lightning 버전 2.6.3

Semgrep 고객을 위한 안내 Semgrep은 이 문제를 다루는 자문(Advisory)과 규칙(Rule)을 제공하므로 프로젝트를 확인할 수 있습니다. 최근 프로젝트 스캔을 실행하지 않았다면 새 스캔을 실행하십시오. 프로젝트에서 이러한 패키지 버전이 최근에 설치되었는지 확인하려면 자문 페이지(https://semgrep.dev/orgs/-/advisories)를 확인하고 일치하는 종속성(Dependency)이 있는지 필터를 점검하세요. "일치하는 종속성 없음(No matching dependencies)"으로 표시되면 프로젝트에서 악성 종속성을 적극적으로 사용하고 있지 않은 것입니다. 일치하는 항목이 있다면 복구 및 침해 지표에 대한 추가 조언은 아래에 나와 있습니다.

일치하는 경우 조치 사항: 아래 IOC에 나열된 주입된 파일(예기치 않은 내용이 포함된 .claude/.vscode/ 디렉토리)이 있는지 리포지토리를 감사(Audit)하고, 영향을 받은 환경에 있었을 수 있는 모든 GitHub 토큰, 클라우드 자격 증명(Cloud credentials) 또는 API 키를 교체(Rotate)하십시오.

생태계 간 확산: PyPI에서 npm으로 npm을 직접 공격했던 기존의 mini Shai-Hulud와 달리, 이번 공격의 진입점은 PyPI입니다. 멀웨어 페이로드는 여전히 JavaScript이며, 웜 전파는 npm을 통해 이루어집니다. 실행되면 멀웨어는 npm publish 자격 증명을 찾아 해당 토큰으로 게시할 수 있는 모든 패키지에 setup.mjs 드롭퍼(Dropper)와 router_runtime.js를 주입하고, scripts.preinstall이 드롭퍼를 실행하도록 설정한 뒤 패치 버전을 올려 다시 게시합니다. 이 패키지들을 설치하는 모든 다운스트림(Downstream) 개발자는 자신의 컴퓨터에서 전체 멀웨어를 실행하게 되어 토큰을 도난당하고 패키지가 감염됩니다.

작동 방식 데이터 유출 구성 요소는 지난 캠페인의 "Mini Shai-Hulud" 메커니즘과 설계를 공유합니다. 개별 경로가 차단되더라도 탈취된 데이터가 빠져나갈 수 있도록 4개의 병렬 채널을 사용합니다.

  1. C2 서버로의 HTTPS POST: 탈취된 데이터는 포트 443을 통해 공격자가 제어하는 서버로 즉시 POST됩니다. 도메인과 경로는 페이로드 내에 암호화된 문자열로 저장되어 정적 분석(Static analysis)을 더욱 어렵게 만듭니다.
  2. GitHub 커밋 검색 데드드롭(Dead-drop): 멀웨어는 GitHub 커밋 검색 API를 폴링하여 EveryBoiWeBuildIsAWormyBoi 접두사가 붙은 커밋 메시지를 찾습니다. 해당 메시지는 EveryBoiWeBuildIsAWormyBoi:<base64(base64(token))> 형식으로 이중 Base64 인코딩된 토큰을 포함하고 있습니다. 디코딩된 토큰은 추가 작업을 위해 Octokit 클라이언트를 인증하는 데 사용됩니다.
  3. 공격자 제어의 공개 GitHub 리포지토리: 무작위로 선택된 '듄' 단어로 이름이 지정된 새로운 퍼블릭 리포지토리가 생성되며, "A Mini Shai-Hulud has Appeared"라는 설명이 추가되어 GitHub에서 직접 검색할 수 있습니다. 탈취된 자격 증명은 results/results-<timestamp>-<n>.json(API를 통해 Base64로 인코딩되며 내부는 일반 JSON)으로 커밋되며, 30MB가 넘는 파일은 번호가 매겨진 청크(Chunk)로 분할됩니다. 커밋 메시지는 chore: update dependencies를 위장용으로 사용합니다.
  4. 피해자 자체 리포지토리로 푸시: 멀웨어가 GitHub 서버 토큰인 ghs_를 획득하면, 탈취한 데이터를 피해자의 모든 브랜치에 직접 푸시합니다.
원문 보기
원문 보기 (영어)
The PyPI package &#039;lightning&#039;, a widely-used deep learning framework, was compromised in a supply chain attack affecting versions 2.6.2 and 2.6.3 published on April 30, 2026. Teams building image classifiers, fine-tuning LLMs, running diffusion models, or developing time-series forecasters frequently have lightning somewhere in their dependency tree. Running pip install lightning is all that is needed to activate. The malicious versions contain a hidden _runtime directory with obfuscated JavaScript payload that executes automatically upon module import. The attack steals credentials, authentication tokens, environment variables, and cloud secrets, while also attempting to poison GitHub repositories. It has Shai-Hulud themes including creating public repositories called EveryBoiWeBuildIsaWormBoi. We believe that this attack is the work of the same threat actor behind the mini Shai-Hulud campaign. The IOC structure is consistent with that operation: the malicious commit messages follow the same Dune-themed naming convention, with this campaign using the prefix EveryBoiWeBuildIsAWormyBoi to distinguish it from the original Mini Shai-Hulud attack. Affected Packages - lightning version 2.6.2 - lightning version 2.6.3 For Semgrep Customers Semgrep has an advisory and rule to cover this so you can find to check your projects. Trigger a new scan if you haven&#039;t recently on your projects. Check the advisories page to see if any projects have installed these package versions recently: https://semgrep.dev/orgs/-/advisories Check your dependency filter for matches. If you see “No matching dependencies” you are not actively using the malicious dependency in any of your projects. If you did match, additional advice on remediation and indicators of compromise are below. If you matched: Also audit your repositories for the injected files listed in the IOCs below (.claude/ and .vscode/ directories with unexpected contents), and rotate any GitHub tokens, cloud credentials, or API keys that may have been present in the affected environment. Cross-Ecosystem Spread: PyPI to npm Unlike mini Shai-Hulud, which targeted npm directly, the entry point here is PyPI. The malware payload is still JavaScript, and the worm propagation happens through npm. Once running, if the malware finds npm publish credentials, it injects a setup.mjs dropper and router_runtime.js into every package that token can publish to, sets scripts.preinstall to execute the dropper, bumps the patch version, and republishes. And any downstream developer who installs one of those packages runs the full malware on their machine, has their tokens stolen and packages wormed. How it Works The exfiltration component shares its design with the "Mini Shai-Hulud" mechanism from their last campaign, using four parallel channels so stolen data gets out even if individual paths are blocked. HTTPS POST to C2. Stolen data is immediately POSTed to an attacker-controlled server over port 443. The domain and path are stored as encrypted strings in the payload, making static analysis harder. GitHub commit search dead-drop. The malware polls the GitHub commit search API for commit messages prefixed with EveryBoiWeBuildIsAWormyBoi, which carry a double-base64-encoded token in the format EveryBoiWeBuildIsAWormyBoi:<base64(base64(token))>. Once decoded, the token is used to authenticate an Octokit client for further operations. Attacker-controlled public GitHub repo. A new public repository is created with a randomly chosen Dune-word name and the description "A Mini Shai-Hulud has Appeared", which is directly searchable on GitHub. Stolen credentials are committed as results/results-<timestamp>-<n>.json (base64-encoded via the API, plain JSON inside), with files over 30 MB split into numbered chunks. Commit messages use chore: update dependencies as cover. Push to victim&#039;s own repo. If the malware obtains a ghs_ GitHub server token, it pushes stolen data directly to all branches of the victim&#039;s own GITHUB_REPOSITORY. What Gets Stolen The malware targets credentials across local files, environment, CI/CD pipelines, and cloud providers: Filesystem: Scans 80+ credential file paths for ghp_, gho_, and npm_ tokens (up to 5 MB per file). Shell / Environment: Runs gh auth token and dumps all environment variables from process.env. GitHub Actions: On Linux runners, dumps Runner.Worker process memory via embedded Python and extracts all secrets marked "isSecret":true, along with GITHUB_REPOSITORY and GITHUB_WORKFLOW. GitHub orgs: Checks token scopes (repo, workflow) and iterates GitHub Actions org secrets. AWS: Tries environment variables, ~/.aws/credentials profiles, IMDSv2 (169.254.169.254), and ECS (169.254.170.2) to call sts:GetCallerIdentity; additionally enumerates and fetches all Secrets Manager values and SSM parameters. Azure: Uses DefaultAzureCredential to enumerate subscriptions and access Key Vault secrets. GCP: Authenticates via GoogleAuth and enumerates and fetches all Secret Manager secrets. The targeting covers local dev environments, CI runners, and all three major cloud providers. Any machine that imported the malicious package during the affected window should be treated as fully compromised. Persistence via Developer Tooling Once inside a repository, the malware plants persistence hooks targeting two of the most common developer tools: Claude Code and VS Code. This may be among the first documented instances of malware abusing Claude Code&#039;s hook system in a real-world attack. Claude Code: .claude/settings.json. The malware writes a SessionStart hook with matcher: "*" into the repository&#039;s Claude Code settings, pointing to node .vscode/setup.mjs. It fires every time a developer opens Claude Code in the infected repo — no tool use or user action required beyond launching the session. VS Code: .vscode/tasks.json. A parallel hook targets VS Code users via a runOn: folderOpen task that runs node .claude/setup.mjs every time the project folder is opened. The dropper: setup.mjs. Both hooks invoke setup.mjs, a self-contained Bun runtime bootstrapper. If Bun isn&#039;t installed, it silently downloads bun-v1.3.13 from GitHub releases, handling Linux x64/arm64/musl, macOS x64/arm64, and Windows x64/arm64. It then executes .claude/router_runtime.js (the full 14.8 MB payload) and cleans up from /tmp. Bonus payload: malicious GitHub Actions workflow. If the malware holds a GitHub token with write access, it pushes a workflow named Formatter to the victim&#039;s repository. On every push it dumps all repository secrets via ${{ toJSON(secrets) }} and uploads them as a downloadable Actions artifact named format-results. The actions are pinned to specific commit SHAs to appear legitimate. Any repository that received the infected lightning package during CI and held a token with write access should be audited for these files. Indicators of Compromise Look for a few indicators: A commit message prefixed with EveryBoiWeBuildIsAWormyBoi (dead-drop token carrier, searchable via GitHub commit search) GitHub repos with description: "A Mini Shai-Hulud has Appeared" (attacker exfil repos, directly searchable) Packages - lightning@2.6.2 - lightning@2.6.3 Files / System Artifacts _runtime/start.py Python loader that initializes the payload on import runtime/router runtime.js Obfuscated JavaScript payload (14.8 MB, Bun runtime) _runtime/ Directory added to the malicious package versions .claude/router_runtime.js Malware copy injected into victim repos .claude/settings.json Claude Code hook config injected into victim repos .claude/setup.mjs Dropper injected into victim repos .vscode/tasks.json VS Code auto-run task injected into victim repos .vscode/setup.mjs Dropper injected into victim repos