더 이상 지켜보지 않게 된 의존성을 위한 조기 경보 시스템.
AI 시대에는 유지할 수 있는 것보다 더 많은 프로젝트를 출시하게 됩니다. Sentinello는 그 하나하나를 지켜보며 Node.js 의존성에 숨은 알려진 CVE를 드러냅니다 — 잊힌 프로젝트가 사고로 이어지기 전에.
명령 하나로 실행:
docker run -d \
--name sentinello \
-p 127.0.0.1:3870:3000 \
--stop-timeout 60 \
-v sentinello-data:/app/data \
-v sentinello-nvm:/home/sentinello/.nvm \
-v ~/Developer:/roots/personal:ro \
ghcr.io/walkofcode/sentinello:latestlinux/amd64 및 arm64에서 실행
계정 불필요. SaaS 없음. 텔레메트리 없음. Docker 이미지 하나와 SQLite 파일 하나 — 코드와 발견 결과가 결코 당신의 머신을 떠나지 않습니다.
포털 없이 바로 쓸 수도 있습니다
같은 스캐너를 CLI로도 제공합니다. 설치도 계정도 데이터베이스도 필요 없습니다 — 실행하면 에이전트가 바로 처리할 수 있는 권고문을 출력하고 종료합니다.
npx sentinello파이프로 넘기면 stdout에는 markdown만 흐르므로 권고문이 그대로 에이전트에 전달됩니다:
npx sentinello | claude -p "$(cat -)"폴더를 탐색
디렉터리를 지정하면 그 아래 모든 프로젝트를 찾아냅니다. 각 프로젝트 루트에서 멈추므로 모노레포는 쉰 개가 아니라 한 개로 셉니다. .gitignore와 .sentinelloignore를 존중합니다.
세 가지 소스를 확인
lockfile에서 실제 설치된 정확한 버전을 확인하고 로컬 권고문 캐시와 오프라인으로 대조합니다. 프로젝트마다 네트워크를 호출하지 않으며, 코드는 전혀 업로드되지 않습니다.
권고문을 작성
발견 사항과 조치 프롬프트가 첨부된 날짜별 markdown 파일 — 손대기 전에 분류하고, override보다 상위 패키지 업그레이드를 우선하며, 수정은 lockfile에서 검증하라는 지침이 함께 담깁니다.
npm audit와 무엇이 다른가
npm audit를 대체하지 않습니다. npm audit를 실행한 뒤, npm audit가 볼 수 없는 두 개의 권고문 소스를 더하고 중복되는 항목은 억제합니다.
| npm audit | npx sentinello | |
|---|---|---|
| 범위 | 지금 서 있는 프로젝트 하나. | 폴더 아래 모든 프로젝트를, 한 번의 실행과 하나의 리포트로. |
| 권고문 소스 | 사용 중인 레지스트리의 권고문 피드. | 여기에 OSV와 GitLab gemnasium을 더합니다. 중복은 억제되므로 소스를 추가해도 새로운 발견만 늘어납니다. |
| 악성 패키지 | 다루지 않음. | OSV의 MAL- 레코드가 멀웨어와 함께 배포된 패키지(타이포스쿼팅, 설치 스크립트 페이로드 등)를 실제로 침해된 버전과 대조해 표시합니다. |
| 출력 | 표, 또는 직접 해석해야 하는 JSON. | 조치 프롬프트가 첨부된 markdown 권고문. 에이전트에 바로 넘길 수 있습니다. |
| 대조 방식 | 프로젝트마다 레지스트리 호출. | 로컬 캐시를 대상으로 오프라인 대조. 첫 실행에서 먼저 묻고 내려받으며, 이후 실행은 거의 아무것도 전송하지 않습니다. |
추가 소스는 형식적인 것이 아닙니다. Sentinello 자체 저장소에서 npm audit와 OSV는 각각 세 건을 보고하고 그 내용이 모두 일치하지만, 유일한 critical 발견은 나머지 둘에는 없는 gemnasium에서 나옵니다.
기능
자체 호스팅 포털 하나에 모두 — 외부 서비스 없음, 데이터가 네트워크를 떠나지 않음.
단일 분류 대기열
수십 개의 체크아웃에 흩어진 npm audit 대신, 전체 포트폴리오의 CVE를 한곳에서 보고 분류하세요.
프로젝트별 또는 라이브러리별 탐색
어떤 저장소든 들어가 발견 결과, 수정 버전, 기록을 확인하거나 — 취약한 패키지로 전환해 영향을 받는 모든 프로젝트를 보고 한 번에 모든 곳에서 음소거하세요.
서로 일치하는 발견
여러 소스가 같은 취약점을 보고해도 발견 항목은 하나로 유지됩니다 — 어떤 소스가 일치했는지 함께 담고, 그중 가장 높은 심각도로 등급을 매깁니다.
지속적인 스캔
백그라운드 워커가 일정에 따라 다시 스캔하므로, 확인하는 것을 기억하지 않아도 새 권고가 나타납니다.
다중 소스
npm audit를 넘어 OSV와 GitLab gemnasium 모두와 대조하여 더 넓은 CVE 범위와 알려진 악성 패키지 탐지를 제공합니다.
알림 및 웹훅
실패와 발견 알림을 Slack, Telegram 또는 단순한 웹훅으로 받아보세요 — 루트나 프로젝트 단위로 범위를 지정하고, 선택한 언어로. 자동 수정 에이전트를 위한 JSON 또는 일반 텍스트 페이로드도 제공합니다.
MCP 서버
Claude Desktop, Cursor 등 MCP 클라이언트를 연결해 채팅을 떠나지 않고 발견 항목, 프로젝트, 라이브러리를 조회하고 스캔을 실행하세요.
권고 내보내기
프로젝트나 라이브러리의 발견 결과를 Markdown으로 내보내세요. 팀이나 LLM을 위해 맞춤 설정 가능한 해결 프롬프트가 포함됩니다.
이미지 하나, 파일 하나
Docker 이미지 하나와 SQLite 파일 하나. 데이터베이스 서버도, 메시지 큐도, 클라우드 의존성도 없습니다.
자동 등록되는 Roots
/roots 아래에 마운트한 것은 무엇이든 시작 시 등록되고 스캔됩니다 — 디렉터리 이름이 그 라벨이 됩니다.
프로젝트별 Node
각 프로젝트의 .nvmrc를 존중하여, 고정된 Node 버전을 한 번만 설치하고 캐시합니다.
10개 언어
포털 UI, 스캔 사유 코드, 상태가 10개 언어로 현지화되어 있습니다.
스크린샷
실제 동작 보기 — 몇 개의 데모 프로젝트를 스캔하는 포털. 아무 이미지나 클릭하면 확대됩니다.
비교
Sentinello는 더 무거운 Dependency-Track도, 더 저렴한 Snyk도 아닙니다. 다른 영역을 차지합니다: 아무도 파이프라인에 연결하지 않은 프로젝트의 롱테일입니다.
| Sentinello | Dependency-Track | Snyk | Dependabot | |
|---|---|---|---|---|
| 설정 불필요 — 폴더만 지정 | ~ | ~ | ||
| SBOM / CI 단계 불필요 | ||||
| 실제 해석된 잠금 파일 스캔 | ~ | |||
| 악성 패키지 탐지 | ||||
| 자체 호스팅, SaaS 없음 | ||||
| 단일 이미지 + SQLite | ||||
| AI 네이티브(MCP + 내보내기) | ~ | |||
| 다언어(Python, Go, …) | ||||
| 엔터프라이즈 정책 / VEX | ~ | ~ |
Dependency-Track는 누군가 SBOM 파이프라인으로 계측한 프로젝트만 봅니다. Sentinello는 당신이 잊은 것을 찾습니다. 엔터프라이즈 정책에서는 그쪽이 더 강력합니다 — 이미 성숙한 파이프라인에서 그 도구들을 돌리고 있다면 그대로 두세요. Sentinello는 아무도 지켜보지 않는 나머지 포트폴리오를 위한 것입니다.
우리가 이것을 만든 이유
AI 시대에는 유지할 수 있는 것보다 더 많이 출시하게 됩니다.
이제 한 명의 개발자가 한 해에 열 개가 넘는 프로젝트를 띄우고, 납품하고, 떠납니다 — 마케팅 사이트, 고객 대시보드, 조용히 프로덕션에 올라간 사이드 프로젝트. 예전에는 그것들을 안전하게 지키려면 각 체크아웃에 일일이 SSH로 접속해 npm audit를 직접 돌리거나, Next.js CVE가 터지고 며칠 뒤에야 뉴스 헤드라인으로 알게 되는 식이었습니다. 열 개가 넘는 저장소를 그렇게 챙기는 사람은 없으니, 결국 아무도 하지 않게 됩니다.
치명적인 원격 코드 실행 결함을 가진, 잊힌 의존성 하나면 충분합니다. 더 이상 지켜보지 않게 된 가장 단순한 사이트가 침투 경로가 됩니다.
“그냥 Snyk나 Dependabot을 쓰면 되지 않나요?” 그것들은 당신이 직접 연결해 둔 CI 파이프라인 안에서만 동작합니다 — 그런데 롱테일에는 애초에 파이프라인이 없습니다. Sentinello는 그 나머지 전부를 위한 조기 경보 시스템입니다. 폴더 하나를 가리키면 당신이 잊은 모든 프로젝트를 지켜보고, 새로운 CVE가 사고로 번지기 전에 하나의 대기열에 드러냅니다.
작동 방식
세 단계. 프로젝트에 설치할 에이전트도, 만들 계정도 없습니다.
코드를 가리키세요
저장소를 /roots 아래에 마운트하거나 설정 → Roots에서 추가하세요. 각 디렉터리는 시작 시 자동으로 등록되고 탐색됩니다.
지속적으로 스캔
백그라운드 워커가 일정에 따라 의존성을 알려진 CVE와 대조하며, 필요할 때 각 프로젝트가 고정한 Node 버전을 설치합니다.
하나의 대기열에서 분류
모든 프로젝트의 모든 발견 결과가 심각도로 필터링할 수 있는 하나의 대기열에 모입니다 — Slack, Telegram 또는 웹훅으로의 알림은 선택 사항입니다.
누구를 위한 것인가
Sentinello는 지켜볼 수 있는 것보다 더 많은 것을 프로덕션에 두고 있는 모든 이를 위한 것입니다 — 혼자 개발하는 사람, 작은 팀, 고객 작업을 저글링하는 에이전시.
- 출시 후에도 오랫동안 안전해야 하는 사이드 프로젝트와 고객 사이트를 출시합니다.
- 모든 저장소에 CI를 연결하지 않고도 포트폴리오 전반을 한눈에 보고 싶습니다.
- 코드 인벤토리를 SaaS에 넘기기보다 자체 호스팅하는 편을 선호합니다.
이미 성숙한 파이프라인에 Snyk나 Dependabot을 연결해 둔 대규모 조직이라면 그대로 쓰세요 — Sentinello는 엔터프라이즈 SCA를 대체하려는 것이 아닙니다. 아무도 지켜보지 않는 나머지 포트폴리오를 위한 것입니다. 오픈 소스이며 MIT 라이선스이므로, 무엇을 하는지 정확히 읽어볼 수 있습니다.
릴리스 노트
Sentinello는 자주 업데이트됩니다 — 각 릴리스가 제공한 내용입니다.
하나의 출처가 프로젝트 전체를 대변하던 대시보드
v3.5.0 · 2026. 8. 20.- 대시보드의 <strong>상태</strong> 열은 하나의 출처만 보고하고 나머지는 버렸습니다. 스캔은 출처마다 한 행씩 기록하며 서로 몇 밀리초 차이로 끝나기 때문에, 열에는 마지막에 끝난 것 — 실제로는 언제나 OSV — 이 표시되었습니다. npm audit이 문제없이 스캔해 실제 취약점을 찾아냈는데도 모든 프로젝트가 “OSV 데이터베이스가 아직 다운로드되지 않음”으로 표시된 이유입니다. 이제 상태는 답하지 못한 출처마다 배지를 하나씩, 출처 이름과 함께 표시하고, 활성화된 출처가 모두 정상이면 아무것도 표시하지 않습니다. 스캔 기록에도 같은 이유로 <strong>출처</strong> 열이 추가되었습니다. 한 번의 스캔이 구분할 수 없는 세 줄을 남겼기 때문입니다.
- 설정 → 출처는 캐시를 다시 만드는 중에도 최신이라고 주장했습니다. 포털이 읽는 상태는 동기화가 끝날 때만 기록되었기에, 수 분이 걸리는 재구축 내내 이전 개수를 계속 보여주었습니다 — 그동안 모든 스캔은 반쯤 삭제된 캐시를 올바르게 거부하고 있었는데도 말입니다. 게다가 스캐너가 요구하는 정규화 버전을 한 번도 담지 않아, 버전만 올려도 재구축 없이 같은 거짓 주장이 만들어졌습니다. 이제 이 행은 이전 개수를 흐리게 표시한 <strong>다시 만드는 중…</strong>, 또는 캐시를 쓸 수 없는데 아무도 손대지 않고 있을 때는 <strong>재구축 대기 중</strong>으로 표시됩니다.
- 캐시 다운로드가 끝나도 모든 프로젝트는 캐시가 없던 동안 받은 판정에 그대로 묶여 있었습니다. 다시 스캔하는 것이 없어 <code>osv_db_not_seeded</code>는 다음 예약 스캔까지, 또는 직접 알아차리고 스캔을 누를 때까지 남아 있었습니다. 이제 Sentinello는 캐시가 다시 사용 가능해지는 즉시 전체 재스캔을 한 번 대기열에 넣습니다. 증분 업데이트는 아무것도 넣지 않습니다. 업그레이드도 포함됩니다. 캐시가 완료되기 전의 판정을 프로젝트가 그대로 안고 있는 인스턴스에 이 릴리스가 올라가면, 워커가 첫 부팅에서 그 불일치를 발견해 대신 정리합니다 — 잊지 않고 스캔을 눌러야 할 일이 없습니다.
문제를 고친 버전을 취약하다고 알린 권고
v3.4.0 · 2026. 8. 18.- gemnasium은 일부 권고를 비교 연산자와 버전 사이에 공백을 두고 작성합니다 — <code><0.5.2</code>가 아니라 <code>< 0.5.2</code>입니다. 파서는 이 쌍을 서로 다른 두 토큰으로 읽었습니다. 홀로 남은 <code><</code>는 빈 경계를 갖게 되고, 따로 떨어진 버전은 정확히 고정된 버전으로 캐시되었습니다. 그래서 <code>fresh</code> 권고는 0.5.2를 취약하다고 보고했습니다. 0.5.2가 바로 그 문제를 고친 릴리스인데도 말입니다. 게다가 사용할 수 있는 수정이 없다고 보고했습니다. 고정된 버전은 업그레이드 대상을 전혀 갖지 않기 때문입니다. 이렇게 작성된 권고가 19건이고 그 전부가 잘못 해석되었습니다. 15건은 범위를 통째로 잃었고, 7건은 기록 자체가 수정 버전으로 명시한 버전을 고정했습니다. <code>pg</code>는 열한 개를 고정했습니다.
- Sentinello는 npm의 범위 문법을 직접 해석하는 일을 그만두고, 이제 모든 범위를 먼저 npm 자체 구현에 넘깁니다. 이것으로 잘못된 해석의 한 부류 전체가 한꺼번에 사라집니다. npm에게 <code><=3.3</code>은 “3.3 계열의 끝까지”를 뜻합니다. 글자 그대로 읽으면 3.3.0에서 멈춰 3.3.1을 놓쳤는데, 이는 실제 <code>converse.js</code> 권고입니다. 또 <code>=103</code>은 하나의 점이 아니라 103 계열 전체를 뜻하며, <code>binaryen</code>이 여덟 건에서 그렇게 기술합니다. 캐럿, 물결표, <code>1.x</code>, 하이픈 범위도 이제 읽습니다. 이전에는 그중 어느 형태로 작성된 기록이든 아무 말 없이 버려졌습니다. gemnasium이 npm용으로 공개하는 서로 다른 버전 범위 4,696개 전부에서 확인한 결과, 직접 해석하면 npm과 9건이 어긋났고 위임하면 하나도 어긋나지 않습니다. 영향을 받는 것은 npm뿐입니다. 파이썬의 <code>==1.0</code>은 와일드카드가 아니라 정확한 버전이므로, 그곳에 npm 규칙을 적용하면 없는 탐지를 만들어 냅니다.
- npm의 해석이 패키지를 설치할 때는 옳지만 권고로서는 그른 세 가지는 적용하지 않습니다. 버전을 전혀 지목하지 않는 범위 — <code>*</code>, <code>x</code>, 빈 필드 — 는 npm이 설치할 때는 “아무 버전”을 뜻하지만 권고에서는 “아무도 채우지 않았다”와 구별되지 않습니다. 그래서 공개된 모든 릴리스에 대한 탐지로 바꾸지 않고 거부합니다. 끝에 남은 <code>||</code>가 그 앞의 범위를 전체로 넓히는 일도 이제 없습니다. 그리고 <code>>0</code>은 계속 모든 버전을 뜻합니다. <code>pandora-doomsday</code>가 악성 패키지를 그렇게 기술하고 있고, npm의 해석대로면 0.x 전체가 깨끗하다고 판정되기 때문입니다. 별개로, 명시된 수정 버전이 자기 영향 범위의 시작과 같거나 그보다 아래에 있는 권고에는 더 이상 그 값을 경계로 끼워 넣지 않습니다. 아무것과도 일치하지 않는 구간, 즉 조용히 보고를 멈추는 탐지를 만들어 냈기 때문입니다. 그리고 그런 구간을 버리는 규칙은 이제 소스마다 따로 쓰지 않고 OSV와 공유합니다. 따로 쓴 것이야말로 두 소스가 어긋나기 시작한 이유였습니다.
- 이 모든 것을 계속 놓쳐 온 테스트는 이제 입력을 나열하는 대신 생성합니다. gemnasium이 npm용으로 공개하는 서로 다른 버전 범위 전부를 빌드마다 npm 자체 구현과 대조하고, 범위 문법의 전체 조합과 OSV 범위 이벤트의 모든 순서도 함께 검증합니다. 이전 릴리스를 대상으로 실행하면 이 일괄 검사는 28개 범위에서 실패합니다. 이것이 대체한 손으로 쓴 예제 열 개는 모두 통과했습니다. 앞으로 업스트림이 새로운 표기를 만들어 내더라도, 누군가 그로 인해 생긴 탐지 결과를 알아차릴 때가 아니라 처음 가져오는 시점에 빌드가 실패합니다.
- 이 결과를 만들어 내는 코드의 모든 부분이 이제 테스트로 실행됩니다. 구문, 분기, 함수, 라인 모두 100%이며 저장소 전체에 예외가 하나도 없습니다. 최근 몇 번의 릴리스에서 결함이 새어 나온 이유에 대한 직접적인 답이기도 합니다. 하나같이 아무것도 실행하지 않는 분기였고, 아무 일도 하지 않은 채 성공을 보고했습니다. 마지막 109개를 막는 과정에서 도달할 수 없는 안전장치로 기록돼 있던 것 중 상당수가 실은 그저 테스트되지 않았을 뿐이라는 사실이 드러났고, 가리키던 파일이 옮겨진 뒤로 몇 달 동안 아무것도 검사하지 않던 커버리지 규칙도 발견됐습니다. 그 규칙과 주변의 예외 500줄은 규칙 하나로 대체되어, 이제 테스트 없는 코드는 평균을 낮추는 대신 빌드를 실패시킵니다.
- 마지막 방어 공백도 닫았습니다. 읽을 수 없는 OSV 상한은 유효한 구간을 열린 채로 두고, 대체 경계는 적용 후 검증하며, <code><1.2.3-0</code> 같은 명시적 npm 프리릴리스 경계는 정확한 의미를 유지합니다.
모든 버전이 취약하다고 주장하던 권고
v3.3.2 · 2026. 8. 17.- 영향 범위에 끝이 없는 권고는 모든 버전에 영원히 일치합니다. 어떤 업그레이드로도 해소할 수 없는 결과이며, 화면에서는 실제로 패치되지 않은 취약점과 구별되지 않습니다. <code>xlsx</code> 권고 두 건이 바로 그런 상태로 들어와, 이미 완전히 패치된 0.20.3을 높음 심각도에 수정 불가로 11개 프로젝트에서 동시에 보고했습니다. 반면 <code>npm audit</code>은 같은 두 건을 0.19.3과 0.20.2에서 수정됨으로 정확히 보고했습니다. 원인은 상류에 있고 의도적입니다. GitHub은 해당 패키지 이름으로 레지스트리가 제공하지 않는 수정 버전을 명시하지 않습니다. SheetJS는 0.19.3 이후를 자사 CDN에서만 배포하므로, GitHub은 범위를 “0부터 전부”로 적고 실제 경계는 별도 필드에 기록합니다. Sentinello는 그 필드를 읽지 않았고, 이제는 읽습니다. 영향을 받은 npm 권고는 15건이며 <code>babel-traverse</code>와 <code>sandbox</code>도 포함됩니다. 실제로 수정이 없는 480건은 그대로 그렇게 표시되고, 이미 자체 경계를 명시한 레코드는 절대 덮어쓰지 않습니다
- 수정 버전을 나열하면서도 범위를 열어 두었던 gemnasium 권고는 이제 그중 가장 높은 버전으로 상한이 지정됩니다. 끝이 없는 범위는 앞으로 나올 릴리스까지 취약하다고 주장하는 셈인데, 수정 버전을 명시한 레코드가 그런 뜻일 수는 없습니다
- gemnasium은 Python 버전 범위를 PEP 440 교집합 — <code>>=5.0,<5.8</code> — 으로 적는데, 파서가 토큰을 공백으로만 나누는 바람에 전체가 하나의 토큰이 되어 하한은 읽을 수 없고 상한은 아예 사라졌습니다. 이런 범위는 아무것도 일치시키지 못하며, 아무것도 일치시키지 못한다는 것은 아무것도 보고하지 않는다는 뜻입니다. 캐시된 PyPI 레코드 7,159건 중 2,830건이 그 상태였습니다. 이는 3.3.0에서 Python, Go, Rust를 내린 세 가지 이유 중 하나였습니다. 나머지 두 가지는 아직 해결되지 않았으므로 이들은 계속 내려간 상태로 남습니다
3.3.0과 같은 릴리스, 다만 빌드되는 Docker 이미지 포함
v3.3.1 · 2026. 8. 15.- 3.3.0은 npm과 GitHub에는 게시되었지만 컨테이너 이미지 빌드가 실패해 릴리스 시점에는 GHCR과 Docker Hub에 3.3.0이 없었습니다. Dockerfile은 설치할 워크스페이스 패키지를 하나씩 나열하는데, 그중 버전 비교 패키지만 처음부터 빠져 있었습니다. 이번 릴리스 전까지는 이미지 안의 어떤 것도 그 패키지를 import하지 않았기 때문에 이 누락이 한 번도 드러나지 않았습니다. 이후 3.3.0 자체의 애플리케이션 코드로 빌드한 수정된 3.3.0 이미지를 게시했으므로 <code>docker pull sentinello:3.3.0</code>은 다시 동작합니다. 3.3.1은 같은 수정을 소스 트리에 반영한 것입니다. CLI를 쓰신다면 3.3.0으로 이미 문제가 없습니다.
실제로 동작하는 생태계만 — 그리고 믿을 수 있는 알림
v3.3.0 · 2026. 8. 15.- 알림이 비어 있는 채로 도착할 수 있었습니다. 한 운영자는 어떤 프로젝트에 취약점이 있다고 알리면서 하나도 나열하지 않은 텔레그램 메시지를 받았습니다. 발송은 프로젝트 단위로 한정되지만 실행은 스캐너마다 이루어졌기 때문에, npm audit 차례가 대기 중인 OSV 이벤트 두 개를 넘겨받고 어느 것과도 매칭하지 못한 채 빈 목록 위에 제목만 그렸습니다. 그러고는 두 이벤트를 모두 전달됨으로 표시했고 — 한 번도 언급되지 않은 두 건의 발견이 알림 완료로 기록되었으며, 전달된 이벤트는 다시 검토되지 않습니다. 이제 이벤트는 설명할 수 있을 때만 발송되고, 그렇지 못한 이벤트는 대기 상태로 남아 다음 스캔에서 다시 검토됩니다
- 발견 항목은 어떤 소스든 매긴 가장 높은 등급으로 보고되며, 이 상향은 대시보드와 프로젝트 합계, CLI의 <code>--fail-on</code> 게이트에는 도달했지만 알림 임계값에는 도달하지 못했습니다. 알림이 교차 확인보다 먼저 실행되어, 이벤트에는 살아남은 소스 자신의 등급이 찍힌 뒤 다시 기록되지 않았기 때문입니다. 실제 인스턴스에서 열린 발견 135건이 실제보다 낮은 이벤트 심각도를 갖고 있었고, <strong>그중 41건은 critical을 low·high·moderate로 기록</strong>하고 있었습니다. critical과 high로 필터링한 대상은 그 어떤 것에 대해서도 영구히 호출되지 않았을 것입니다
- 예약된 스캔이 이어지지 않고 자정에 멈췄습니다. “07:00부터 3시간마다”는 07, 10, 13, 16, 19, 22시에 실행된 뒤 다음 날 07:00까지 멈춰 있었습니다 — 하루 여덟 번이 아니라 여섯 번, 매일 밤 아홉 시간의 사각지대와 함께 — 그동안에도 설정 화면은 선택한 간격을 그대로 보여주었습니다. “20:00부터 6시간마다”는 하루 한 번에 그쳤습니다. 이제 시간대가 날짜를 넘어 이어집니다
- <strong>Python, Go, Rust를 철회했습니다.</strong> 거친 부분에 대한 신중함이 아닙니다. 이들의 결함은 “깨끗함”으로 보고되었습니다. 수정 버전 도출과 버전 정렬이 semver 전용이라, Django에 대한 OSV 권고가 설치된 4.2에 “3.2.23으로 업그레이드”를 권했습니다. OSV의 PyPI 패키지 이름은 PEP 503으로 정규화되어 있지 않아 리졸버의 이름과 결코 만나지 못합니다. gemnasium의 범위 파서는 PEP 440의 쉼표 교집합을 읽지 못합니다. 잘못된 이유로 “취약점 없음”이라 답하는 소스는 아예 제공하지 않는 편보다 나쁘므로, 제품 표면에서 완전히 사라졌습니다 — 스위치도, 탐색도, 다운로드도 없습니다. <strong>이미 수집한 발견 항목은 계속 보이고 음소거할 수 있으며, 아무것도 삭제되지 않습니다.</strong> npm 생태계의 표시 이름은 이제 <strong>Node.js</strong>이며, 언어가 아니라 실제로 스캔하는 패키지 생태계를 가리킵니다
- <strong>설정 → 소스</strong>도 그에 맞춰 다시 만들었습니다. 이전에는 각 소스가 자기 스위치 옆에서 같은 설명을 반복했고, 캐시 기반 소스는 저마다 다섯 줄짜리 상태 패널과 전체 크기의 “지금 새로 고침” 버튼을 달고 있었습니다 — 그 버튼은 몇 번 나타나든 소스당 하나의 공유 신호만 큐에 넣는데도 말입니다. 이제 스위치는 소스가 켜져 있는지만 말하고, 각 소스가 무엇을 더하는지, 무엇을 어디서 내려받는지, 언제 실행되는지는 그 아래 하나의 참조 표로 옮겼으며, 동기화 상태는 한 줄로 줄었습니다
- npm 자신의 lockfile이 프로덕션에서 도달 가능하다고 선언한 패키지가 개발 전용으로 강등되고 있었습니다. lockfile에 <code>dev: true</code>가 없다는 것은 그 패키지가 프로덕션에서 도달 가능하다는 npm의 주장이며, 루트 매니페스트가 할 수 있는 것보다 강한 진술입니다. 그런데 리졸버는 그 이름이 <code>devDependencies</code>에도 나타나기만 하면 이를 덮어썼습니다 — 바로 npm이 옳았던 경우입니다. 실제 프로젝트 130개에서 측정한 결과, 97개 프로젝트에서 142개 패키지가 강등되었습니다 — lodash, semver, postcss, tailwindcss, @babel/runtime — 한 인스턴스에서는 열린 발견 7건이 프로덕션 전용 필터에서 가려졌습니다
- <code>0.0.0-20180523222229-09b5706aa936</code> 같은 버전에 고정된 패키지는 <strong>어떤 권고와도 일치하지 않았습니다</strong>. 상한이 열린 권고에도 걸리지 않았고, 스캔은 발견 0건으로 ok를 보고했습니다. 권고의 하한 <code>introduced: 0</code>이 릴리스 0.0.0으로 비교되는데, semver에서는 프리릴리스가 자기 릴리스보다 아래로 정렬되기 때문입니다. 실제 캐시의 비교 가능한 범위 19,085개 중 330개가 무엇으로도 만족할 수 없는 구간으로 저장되어 있었습니다
- 중단된 OSV 동기화가 권고를 영구히 지울 수 있었습니다. 증분 경로는 권고의 행을 먼저 삭제한 뒤 try/catch 안에서 대체본을 가져왔기 때문에, 타임아웃·5xx·종료 중 무엇이든 그것을 통째로 없앴고 — 그러고도 커서는 그대로 전진해 해당 id를 영구히 뒤에 남겼습니다. 손실은 조용했고 다음 전체 재시딩까지 이어졌으며, 성공으로 보고된 동기화 안에서 일어났습니다. <code>npx sentinello</code>의 캐시도 불안정한 실행마다 같은 방식으로 깎여나갔습니다. 이제 둘 다 먼저 가져오고 나중에 교체합니다
- CLI의 <code>--dep-type dev</code>는 “dev에서 도달 가능하기만 하면”을 뜻했지만 포털은 “<em>오직</em> dev에서만 도달 가능”을 뜻합니다. 그래서 양쪽에서 도달 가능한 패키지는 한쪽 화면에만 나타났습니다 — 한 인스턴스에서 두 해석 사이에 열린 발견 177건이 어긋납니다. CLI는 이제 포털의 규칙을 쓰며, 구조적으로 읽을 수 없었던 OSV의 <code>withdrawn</code> 필드도 존중합니다: 실제 npm 캐시의 585개 행이 이 값을 갖고 있었고, 그 전부가 유효한 발견으로 보고되고 있었습니다
- 취약점이 어떤 버전 <em>이후</em>부터 시작한다고 말하는 gemnasium 권고 — <code>>=1.2.8</code>이 아니라 <code>>1.2.8</code> — 가 경계 버전 자체도 영향을 받는 것처럼 읽히고 있었습니다. 2021년 <code>rc</code> 패키지 탈취 권고가 정확히 그렇게 쓰여 있고, 1.2.8은 그 마지막 깨끗한 릴리스, 즉 권고 자체의 조치 안내가 그대로 머무르라고 말하는 바로 그 버전입니다. 그래서 <code>rc</code>가 설치된 모든 프로젝트에 수정본도 없는 심각 멀웨어 발견이, 한 번도 손상된 적 없는 버전에 대해 표시되었습니다. 이제 경계는 권고가 밝힌 그대로 유지되며 이런 형태의 거짓 심각 항목은 사라집니다
- 같은 반올림이 반대 방향으로도 작동해 진짜 발견을 감추고 있었습니다. <code><=2.0.0</code>으로 제한된 권고는 “2.0.0 미만”으로 저장되어, 가장 분명히 지목된 2.0.0이 보고되지 않았고, 영향받는 버전을 정확히 하나만 지목한 권고는 빈 구간이 되어 통째로 버려졌습니다. 늘 존재했지만 보이지 않던 발견이 조금 새로 나타날 것입니다
- Sentinello가 구현하지 않은 문법으로 쓰인 범위 — <code>^1.0.0</code>, <code>~1.0.0</code> — 는 그 문자열 자체를 정확한 버전으로 고정해 저장했기 때문에, 캐시에 남아 있는 한 무엇과도 일치할 수 없었습니다. 살아 있어 보이지만 결코 발동하지 못하는 권고였죠. 이제 이런 레코드는 작동할 수 없는 형태로 저장하는 대신 거부하며, 상한에 깨끗한 수정 버전이 없는 권고에도 마침내 업그레이드 제안이 붙습니다
- webhook URL이나 봇 토큰이 로그 줄에 닿기 전에 가려주는 헬퍼가 짧은 값을 그대로 출력하고 있었습니다. 여섯 자 이하는 거부하면서도 앞 여덟 자와 뒤 네 자를 남겼고, 그 두 조각이 맞닿지 않는지는 아무도 확인하지 않았습니다 — 그래서 7자에서 12자 사이의 비밀 값은 모두 온전히 되돌아왔습니다. 이제는 최소 여덟 자를 가리거나 값을 통째로 가립니다
이제 어떤 소스가 일치하는지 보여주고, 철회된 권고는 보고하지 않습니다
v3.2.0 · 2026. 8. 15.- 여러 권고 데이터베이스가 같은 취약점을 보고할 때 Sentinello는 언제나 하나의 결과만 유지해 왔습니다 — 세 데이터베이스가 안다고 해서 같은 결함을 세 번 보고하는 것은 잡음이기 때문입니다. 다만 이전에는 합쳐진 소스에 대한 정보를 모두 버렸기 때문에, npm audit과 OSV, GitLab gemnasium이 각각 독립적으로 확인한 취약점이 한 데이터베이스만 알고 있던 것과 똑같아 보였습니다. 실제 인스턴스에서는 이것이 전체 결과의 3분의 2에 해당합니다. 이제 각 결과는 그것을 보고한 다른 소스들을 함께 지니며, 해당 배지가 살아남은 항목 옆에 표시됩니다
- 결과는 어떤 소스든 부여한 가장 높은 심각도로 보고됩니다. 데이터베이스들은 실제로 서로 다르게 평가합니다 — gemnasium은 CVSS 벡터로 계산하고 npm audit은 GitHub의 등급을 따릅니다 — 스캐너에게는 신중한 쪽 해석이 행동의 기준이 됩니다. 이는 겉모습만의 변화가 아닙니다. 상향된 결과는 대시보드, 프로젝트 합계, CLI의 <code>--fail-on</code> 게이트, 알림 임계값 모두에서 등급 구간이 바뀝니다. 업그레이드 후 첫 스캔에서 수치가 달라질 수 있지만, 새로 발견된 것은 없고 같은 결과를 더 신중하게 평가한 것입니다
- 소스 간에 평가가 갈리는 경우, 결과의 심각도 옆에 각 소스가 실제로 무엇이라고 했는지 — 해당 소스의 권고 식별자와 등급 — 를 여는 컨트롤이 나타납니다. 설명할 이견이 있을 때만 표시되므로 모두가 같게 평가한 결과는 깔끔하게 유지됩니다
- OSV는 철회를 전용 필드에 기록하고 GitHub은 철회된 권고를 <code>npm audit</code>이 보기도 전에 제거하지만, GitLab gemnasium의 스키마에는 그런 필드가 없습니다. gemnasium은 레코드를 그 자리에서 다시 써서 철회합니다 — 제목이 “False Positive”, “Withdrawn Advisory: …”, “Duplicate Advisory: …”로 바뀌는 한편, 이전에 지목했던 버전은 그대로 남습니다. Sentinello는 그 버전을 읽고 GitLab이 명시적으로 거둬들인 결과를 보고하고 있었습니다. JavaScript, Python, Go, Rust에 걸쳐 383건이며, 그중에는 “False Positive”라는 제목으로 <code>express</code>를 보고한 것도 있습니다. 이제 모두 폐기되며, 383건 중 278건이 다른 권고와 중복되어 철회된 것이므로 중복 결과 한 부류도 함께 사라집니다
- 이 검사는 철회 표식을 정확히 일치시키며 본문 아무 곳에서나 단어를 찾지 않습니다. 따라서 오탐 자체를 다루는 실제 권고는 계속 보고됩니다 — “Cosign’s verify-blob-attestation reports false positive when payload parsing fails”라는 제목의 Cosign CVE-2026-39395는 영향을 받지 않습니다
- gemnasium 캐시는 이번 업그레이드 후 첫 동기화에서 스스로 다시 만들어지며 그때 철회된 권고가 사라집니다. 따로 할 일은 없고 매일 동기화에서 처리되며, 설정 → 소스 → 새로 고침에서 즉시 실행할 수도 있습니다
권고의 버전 범위가 양방향 모두 정확해졌습니다
v3.1.1 · 2026. 8. 14.- 일부 GitLab gemnasium 권고에는 기계가 읽을 수 있는 버전 범위가 전혀 없습니다 — JavaScript 10,777건 중 698건입니다. Sentinello는 그 공백을 “나열된 첫 번째 수정 버전보다 낮은 모든 버전이 영향을 받는다”고 가정해 메워 왔지만, 이 목록은 정렬되어 있지 않고 릴리스 브랜치마다 수정 버전이 하나씩 들어 있어 그 추측이 자주 엉뚱한 브랜치를 가리켰습니다. protobufjs 7.6.5는 해당 브랜치가 7.5.5에서 수정되었는데도 심각한 원격 코드 실행으로 보고되었고, 서로 다른 세 권고가 각각 8.0.5 미만의 모든 vite 버전이 취약하다고 주장했습니다. 이제 Sentinello는 범위를 지어내지 않습니다. 다른 식별자로 게시된 동일한 권고, 권고 자체의 설명, 또는 OSV를 켜 둔 경우에 한해 사용자 컴퓨터에 이미 있는 OSV 사본에서 실제 범위를 복구하며, 어느 것으로도 확인되지 않으면 추측하지 않고 해당 레코드를 폐기합니다. 일부 심각 등급 결과가 사라질 것입니다
- OSV는 여러 릴리스 브랜치에서 수정된 권고를 브랜치마다 별도 항목으로 기술하는데, Sentinello는 첫 번째만 남기고 나머지를 버렸습니다 — JavaScript만으로 1,927개의 취약한 버전 범위이며, 하나하나가 더 이상 보이지 않게 된 실제 취약점입니다. minimatch 권고는 여덟 개 브랜치를 포함하지만 하나만 살아남아, 설치된 minimatch 3.0.4나 9.0.0이 보고되지 않았습니다. next와 ua-parser-js도 같은 방식으로 브랜치를 잃었습니다. 이제 모든 브랜치가 유지됩니다. 새로운 결과가 나타날 텐데, 그 취약점들은 늘 있었고 단지 보이지 않았을 뿐입니다
- 이번 업그레이드 후 첫 동기화에서 두 권고 캐시 모두 스스로 다시 만들어집니다. 저장된 범위가 이전 코드로 생성된 것이기 때문입니다. 따로 할 일은 없으며 매일 동기화에서 처리됩니다. 기다리고 싶지 않다면 설정 → 소스 → 새로 고침에서 즉시 실행할 수 있습니다
음소거한 발견 항목이 화면에서 비켜서고, 데이터베이스도 무한정 커지지 않습니다
v3.1.0 · 2026. 8. 13.- 음소거한 발견 항목은 이미 내린 결정입니다. 그래서 이제 흐리게 남아 있지 않고 프로젝트 페이지에서 완전히 빠집니다. 단순히 깔끔해지는 문제가 아닙니다. 제목의 건수, 두 탭의 배지, 페이지 넘김, 라이브러리별 합계, 내보내기 버튼까지 페이지의 모든 숫자가 같은 데이터에서 계산되므로, 페이지가 마침내 대시보드·MCP 도구·권고 내보내기와 일치합니다. 이 셋은 이미 음소거 항목을 제외하고 있었습니다. 필요할 때는 ‘음소거 항목 표시’로 언제든 되돌릴 수 있으며, 발견 항목이 *전부* 음소거된 프로젝트에서도 마찬가지입니다
- 대화상자에 입력할 때 한 글자 만에 포커스를 잃는 일이 사라졌습니다. 이 결함 때문에 음소거 대화상자의 ‘사유’ 항목을 사실상 채울 수 없었습니다. 필수 항목이자, 몇 달 뒤 그 음소거가 타당했는지 확인할 수 있는 유일한 근거인데도 말입니다. 같은 대화상자가 자신을 연 표 행의 정렬을 물려받는 문제도 해결했습니다. 발견 항목을 음소거할 때는 내용이 오른쪽으로 정렬되고 프로젝트를 음소거할 때는 그렇지 않았던 이유가 이것입니다
- 스캔 기록이 더 이상 끝없이 쌓이지 않습니다. 지금까지 오래됐다는 이유로 스캔 행을 지우는 장치가 전혀 없었기 때문에, 디스크에 남아 있는 프로젝트는 소스마다 매 스윕마다 행을 무한정 쌓았습니다. 실제 인스턴스는 석 달도 안 되어 2.2 GB에 이르렀습니다. 이제 설정 → 고급에 보존 기간이 있고(기본 90일), 워커가 매시간 그보다 오래된 기록을 정리하면서 프로젝트마다 최근 100건은 항상 남깁니다. 발견 항목, 음소거, 알림 기록은 절대 지워지지 않으며 대상은 스캔 로그뿐입니다. 기본값 90일이면 업그레이드한 인스턴스가 첫 실행에서 아무것도 지우지 않습니다. 기록이 실제로 그 기간을 넘어서거나 직접 값을 낮췄을 때 비로소 정리가 시작됩니다
- 그 증가분의 대부분은 `npm audit`의 원본 출력이었습니다. 성공한 스캔마다 통째로 저장되면서도 어디에서도 읽히지 않았고, 해당 인스턴스 데이터베이스의 98.7%를 차지했습니다. 이제 스캔은 짧은 요약만 기록하므로 한 행이 약 79 KB에서 100바이트 남짓으로 줄어듭니다. 상한선도 두어 어떤 스캐너도 같은 일을 반복할 수 없습니다
- MCP에서는 `get_dashboard_summary`가 음소거한 프로젝트를 합계에서 제외하는 반면 `list_projects`는 여전히 반환한다는 점을 명시합니다. 둘은 의도적으로 서로 다른 모집단을 세며, 이를 비교한 에이전트가 결함으로 오해하고 있었습니다. `list_scans` 역시 각 스캔의 스캐너 원본 출력을 더 이상 반환하지 않습니다. 한 번의 응답이 16 MB에 이르기도 했기 때문입니다
gemnasium 다운로드가 다시 동작하고, CLI가 터미널을 반환합니다
v3.0.1 · 2026. 8. 4.- 3.0.0에서는 모든 사용자의 GitLab gemnasium 다운로드가 `HTTP 406`으로 실패했습니다. Node 내장 fetch는 프로그램이 제거할 수 없는 `Sec-Fetch-Mode: cors` 헤더를 붙이고, GitLab은 그 헤더가 있는 저장소 아카이브 요청을 모두 거부합니다 — 따라서 네트워크나 IP, 재시도 횟수와는 무관했습니다. 이제 다운로드는 일반 HTTPS 요청을 사용하며 성공합니다
- 아카이브를 브랜치 이름이 아니라 커밋 ID로 가져옵니다. 같은 업스트림 커밋에서 갱신하는 모든 사용자가 캐시된 사본 하나를 공유하므로, 각자 GitLab에 60MB 아카이브 생성을 요청할 필요가 없습니다. 7분 가까이 걸리던 첫 다운로드가 이제 몇 초 만에 끝납니다
- CLI는 모든 작업을 마치고도 — 보고서를 쓰고 요약을 출력한 뒤에도 — 터미널을 돌려주지 않았습니다. 다운로드 연결이 뒤에서 열린 채 프로세스를 살려 두었기 때문입니다. 이제 아카이브를 다 읽는 즉시 닫습니다
- 다운로드를 거부당한 소스가 이를 알리기까지 3분을 멈춰 있지 않습니다. 몇 초 안에 알리고, 터미널에서는 재시도를 제안합니다 — 실제로 실패한 소스만 다시 시도합니다
- `--fail-on`이 양방향으로 정직해졌습니다. 권고 소스를 조회할 수 없었던 실행은, 수행한 적 없는 깨끗한 스캔으로 보고하는 대신 거부합니다. 또한 `SENTINELLO_OSV_FEED_URL=off`나 `SENTINELLO_GEMNASIUM_FEED_URL=off`로 직접 끄고 한 번도 내려받지 않은 소스 때문에 실행이 실패하지 않습니다
이제 포털 없이도 Sentinello를 쓸 수 있습니다
v3.0.0 · 2026. 8. 3.- 스캐너가 npm의 CLI로 제공됩니다. `npx sentinello`는 폴더를 흔어 그 아래 모든 프로젝트를 찾고 npm audit, OSV, GitLab gemnasium과 대조한 뒤 조치 프롬프트가 막부된 markdown 권고문을 작성합니다. 설치도 계정도 데이터베이스도 필요 없고, 코드가 머신 밖으로 나가지도 않습니다
- 파이프로 넘기면 stdout에는 권고문만 흐르므로 `npx sentinello | claude -p "$(cat -)"`이 문서를 훼손하지 않고 완전한 작업 목록을 에이전트에 전달합니다
- 첫 실행에서 다운로드가 거부되어 gemnasium 소스를 잃는 일이 없어졌습니다. GitLab은 아카이브를 한두 분씩 거부하는데 기존 재시도는 13초 만에 포기했습니다. 이제 CLI는 끝까지 기다리고, 기다리는 이유를 알려주며, 기본값 3분이 맞지 않으면 `--feed-wait`을 받습니다
- 두 다운로드 예상치 모두 추측이 아니라 실측했습니다. OSV의 npm 익스포트는 196MB가 아닌 204MB로, gemnasium 아카이브는 80MB가 아닌 52MB로 표시됩니다. 동의 프롬프트는 추정치에 물결표를 붙여 서버가 알려준 크기와 혼동되지 않게 합니다
- 옵션처럼 생긴 값은 이제 그대로 받아들이지 않고 거부합니다. `--out --`은 예전에 프로젝트 안에 `--`라는 이름의 파일로 권고문을 쓰고 성공했다고 알렸습니다
- 릴리스에 담긴 내용이 많아도 새 소식 패널이 창 아래로 넘치지 않습니다
권고 문서가 실제로 도착합니다 — 집계도 정확하게
v2.6.0 · 2026. 7. 29.- get_project_advisory가 이제 문서 자체를 반환합니다. 지금까지 연결된 클라이언트는 파일 이름과 건수 같은 메타데이터만 받았고, 전체 작업 목록이라고 설명된 문서 본문은 전달되지 않았습니다
- 권고 내보내기가 스캐너 행 단위가 아니라 개별 권고 단위로 한 항목씩 묶입니다. npm audit과 OSV가 함께 보고하는 취약점은 두 개의 비슷한 항목이 아니라 두 권고 ID를 모두 담은 하나의 작업 항목이 됩니다. 포털의 .md 다운로드에도 동일하게 적용되며, 건수가 대시보드와 일치합니다
- MCP 응답 하나에 담기지 않는 큰 프로젝트는 이제 페이지로 나뉩니다. 문서가 불완전함을 밝히고 나머지를 가져올 정확한 호출을 알려주므로, 에이전트가 잘린 뒷부분을 깨끗한 것으로 잘못 읽지 않습니다
- 모든 MCP 도구의 모든 입력에 설명이 붙었고, unmute에 필요한 뮤트 ID를 확인할 수 있는 list_mutes 도구가 추가되었습니다 — 이전에는 같은 세션에서 뮤트를 만든 경우에만 알 수 있었습니다
- 심각도 집계의 허점을 고쳤습니다. 알려진 다섯 값에 없는 심각도를 가진 발견은 건수에는 포함되지만 어느 등급에도 들어가지 않아, 그 하나만 있는 프로젝트가 완전히 깨끗해 보였습니다
MCP에서 바로 받는 권고 내보내기
v2.5.0 · 2026. 7. 28.- 연결된 MCP 클라이언트는 새 get_project_advisory 도구로 프로젝트의 전체 Markdown 권고 문서를 가져올 수 있습니다 — 포털의 「.md 다운로드」 버튼과 같은 문서를 브라우저에서 복사하지 않고 사용할 수 있습니다
- 음소거한 발견 항목은 이제 프로젝트 권고 내보내기에서 제외되므로, 이미 위험을 수용한 작업이 에이전트에게 전달되지 않습니다
- 참고: 권고 문서에는 내보내기 프롬프트가 포함되므로, 이제 MCP 클라이언트가 설정 → 내보내기에 작성한 내용을 읽을 수 있습니다
잘리지 않는 팝업과 더 엄격한 내보내기 프롬프트
v2.4.3 · 2026. 7. 26.- 드롭다운, 의존성 경로 팝오버, 권고 내보내기 메뉴가 자신이 놓인 표나 대화상자에 잘리지 않습니다. 페이지 위에 그려지고, 아래 공간이 부족하면 위쪽으로 펼쳐집니다
- 기본 권고 내보내기 프롬프트가 이제 파일을 고치기 전에 먼저 계획하고, 같은 수정으로 함께 해결되는 발견 항목을 묶고, 버전 변경마다 코드에 미치는 영향을 구체적으로 밝히도록 요구합니다. 목표는 0건이지만 음소거, 버전 범위 완화, 스캔 범위 축소처럼 가짜 0건으로 가는 지름길은 금지하며, 정말로 해결할 수 없는 항목은 날짜가 적힌 잔여 항목 표에 남깁니다
브랜치를 별도 열로
v2.4.2 · 2026. 7. 25.- 프로젝트를 스캔한 git 브랜치가 프로젝트 이름 아래가 아니라 프로젝트 목록의 별도 열에 표시됩니다 — 아이콘 없는 일반 텍스트입니다
깔끔한 종료
v2.4.1 · 2026. 7. 25.- 컨테이너를 재시작해도 기록 중이던 스캔이 중단되지 않으며, 워커가 약 30초간 재시도하지 않고 곧바로 시작합니다
- compose 파일에 stop_grace_period: 60s(또는 --stop-timeout 60)를 설정해 여유를 주세요. README와 Docker 문서에 설명을 추가했습니다
다국어 스캔 — npm에 Python, Go, Rust가 합류했습니다
v2.4.0 · 2026. 7. 25.- Sentinello가 npm과 함께 Python, Go, Rust 프로젝트도 스캔합니다. 잠금 파일은 완전히 오프라인으로 해석되며, 각 프로젝트가 스캔 커버리지(완전, 부분, 감사 불가)를 보고하므로 빈틈이 조용히 묻히지 않습니다
- GitLab의 gemnasium 데이터베이스가 npm audit, OSV와 함께 오프라인 권고 소스로 추가되어 CVE/GHSA 별칭으로 다른 소스와 중복이 제거됩니다. 설정 → 소스는 이제 언어 × 소스 행렬이며 셀별로 알림 범위를 지정할 수 있고, 소스가 하나라도 켜져 있으면 npm audit 자체도 끌 수 있습니다
- 발견 항목에 어느 git 브랜치에서 나왔는지 기록되어 프로젝트 목록, 프로젝트 헤더, 모든 알림에 표시됩니다
- 프로젝트 행에 자체 작업이 생겼습니다. 지금 스캔, 권고 복사 또는 다운로드, 음소거와 해제, 태그 편집을 바로 할 수 있어 분류 작업 때마다 프로젝트로 들어갈 필요가 없습니다
- 프로젝트 대시보드가 약 3.3초에서 약 0.03초로 빨라졌고, 화면 전환 시 멈춘 것처럼 보이는 대신 로딩 상태가 표시됩니다
- 보안: 의존성 권고 25건을 해결했습니다. 포털 이미지 최적화 경로에서 실제로 노출돼 있던 libvips CVE와 배포되는 포털에 영향을 주던 Next.js 권고 9건이 포함됩니다
- 기본 권고 내보내기 프롬프트가 최소 배포 경과 기간, 잠금 파일 검증, 오래된 override를 다루도록 보강됐습니다
더 간단해진 MCP 설정 — 환경 변수 불필요
v2.3.0 · 2026. 6. 9.- 이제 MCP를 설정 → MCP에서 전부 구성합니다: 토큰을 생성하면 /api/mcp 엔드포인트가 켜지고, 지우면 꺼집니다 — SENTINELLO_MCP_ENABLED와 SENTINELLO_MCP_API_TOKEN 환경 변수는 제거되었습니다(기존 환경 변수 토큰은 업그레이드 시 한 번만 가져옵니다)
- Claude Code, Codex, Cursor, Claude Desktop용 붙여넣기만 하면 되는 연결 스니펫, 토큰이 미리 채워져 있습니다
- 환경 변수로 SENTINELLO_PORTAL_BASE_URL을 설정하면 우선 적용되며 부팅할 때마다 다시 적용되므로 설정 → 고급에서 읽기 전용으로 표시됩니다
더 적은 오탐과 스스로 정리되는 발견 항목
v2.2.0 · 2026. 6. 9.- 악성코드 권고가 이제 정확히 영향받는 버전과 대조됩니다 — 한때 침해되었던 패키지라도 깨끗하거나 이미 수정된 버전은 더 이상 표시되지 않습니다
- 중복된 발견 항목이 이제 다음 스캔에서 스스로 해결되어, 오래되었거나 남겨진 항목이 자동으로 정리됩니다
- 프로덕션과 개발 라벨이 이제 모든 소스(npm 및 OSV)에서 일관된 단일 방식으로 계산됩니다
더 깔끔한 프로젝트 헤더와 일관된 필터
v2.1.0 · 2026. 6. 6.- 프로젝트 헤더 간소화 — 제목 옆에서 바로 이름 변경, 음소거와 태그는 아이콘으로
- 의존성 유형 필터 옆의 새 드롭다운에서 소스(npm / OSV)별로 발견 항목 필터링
- 앱 전반의 통일되고 일관된 드롭다운, 시간대 같은 긴 목록은 입력하여 검색 지원
더 명확한 업그레이드 안내
v2.0.1 · 2026. 6. 4.- 2.0 호환성 깨짐 변경에 대한 업그레이드 단계 보강
- README에 localhost 전용 포트 바인딩 명시
다중 소스 스캔과 기본값으로 안전한 강화된 설치
v2.0.0 · 2026. 6. 4.- 선택적 두 번째 소스로서의 OSV(설정 → 소스, 기본값 꺼짐). 악성 패키지 탐지를 갖추고 로컬 캐시의 공개 OSV 데이터베이스와 대조합니다
- 이제 검출 결과가 소스 간에 병합됩니다 — 취약점당 한 행으로, 각 소스를 태그하고 사용 가능한 최선의 수정과 의존성 경로의 합집합을 보여주며, 소스 필터와 의존성 경로 팝오버를 제공합니다
- 보안 강화: MCP 엔드포인트는 기본적으로 꺼져 있고 토큰이 필요하며, 웹훅 전송은 SSRF로부터 보호되고, 선택적 포털 로그인 게이트가 있으며, 컨테이너는 비권한 사용자로 실행됩니다
- 설정이 이제 사이드바와 프로필 페이지를 갖춘 최상위 섹션이 되었습니다
MCP 연동 및 새로운 기능
v1.4.0 · 2026. 5. 29.- Claude Desktop, Cursor 등 클라이언트를 위한 /api/mcp MCP 서버
- 서버 URL과 토큰 관리를 갖춘 새로운 설정 → MCP 섹션
- 새로운 기능 배지와 릴리스 노트 기록
푸터 버전 표시 수정
v1.3.1 · 2026. 5. 28.- 실행 중인 버전이 푸터에 깔끔하게 표시됩니다
알림 개선
v1.3.0 · 2026. 5. 28.- 환경별로 알림 필터링
- 더 간단해진 알림 대상 편집 양식
- 기존 알림 대상 복제
프로젝트 및 라이브러리 페이지
v1.2.0 · 2026. 5. 24.- 홈 화면이 전용 프로젝트 페이지와 라이브러리 페이지로 분리되었습니다
일정 실시간 다시 로드
v1.1.2 · 2026. 5. 24.- 포털에서 변경 사항을 저장하면 워커가 즉시 스캔 일정을 다시 로드합니다
더 안전한 삭제와 더 명확한 업데이트 배너
v1.1.0 · 2026. 5. 23.- 루트와 알림 대상을 삭제하기 전에 확인
- 업데이트 알림이 닫을 수 있는 상단 배너로 이동
- 호스트 마운트가 사라지면 워커가 오래된 루트를 정리합니다
스캐너 정확도 수정
v1.0.1 · 2026. 5. 23.- 설치된 버전이 실제로 취약 범위에 없는 점검 결과 제외
- 발송 기록이 있는 알림 대상을 삭제할 수 있도록 허용
첫 오픈 소스 릴리스
v1.0.0 · 2026. 5. 23.- Sentinello의 첫 공개 릴리스
로드맵
지금 Sentinello는 여러 언어에 걸쳐 당신의 의존성을 지켜봅니다. 앞으로 나아갈 방향과 요청할 수 있는 것을 소개합니다.
더 똑똑한 우선순위
예정악용 가능성과 취약한 코드가 실제로 도달 가능한지를 기준으로 발견 항목의 순위를 매겨 중요한 것부터 처리합니다.
더 많은 통합
예정더 많은 알림 채널과, 팀이 이미 사용하는 도구에 Sentinello를 연결하는 방법.
정적 분석(SAST)
예정의존성의 알려진 CVE뿐 아니라, 당신의 소스 코드에 있는 위험한 패턴도 잡아냅니다.
시크릿 및 라이선스 스캔
예정커밋된 시크릿과 라이선스 문제를 같은 포트폴리오, 같은 대기열에서 표시합니다.
다음에 통합하거나 스캔하고 싶은 것을 알려주세요 — GitHub에 이슈를 열어 로드맵을 함께 만들어요.