
AI 코딩 어시스턴트를 위한 자동화된 의존성 보안 계층으로, npm, PyPI, RubyGems, Maven, Go 및 Rust 생태계 전반에서 패키지의 CVE, 타이포스쿼트, 유기, 버전 수명 문제 및 해시 무결성을 감사합니다.
AI 코딩 어시스턴트(예: Claude)가 프로젝트에 패키지를 추가할 때, 알려진 보안 취약점이 있는지, 패키지가 여전히 활발히 유지 관리되는지, 또는 이름이 악성 유사 패키지와 오타 하나 차이인지 확인하지 않고 그럴듯해 보이는 버전을 선택하는 경우가 많습니다.
safer-dependencies는 Claude Code용 보안 계층입니다. Claude와 매니페스트 파일 사이에 위치하여 보안 검사를 자동으로 실행합니다. 취약한 설치는 실행되기 전에 차단되고, 매니페스트에 기록된 위험한 버전은 기록 직후 디스크에서 수정됩니다. npm, PyPI, RubyGems, Maven, Go, Rust, PHP(Composer) 전반에 걸쳐 CVE, 타이포스쿼팅, 버려진 패키지, 버전 수명 문제와 함께 신규 릴리스의 쿨다운 기간 등 위험한 종속성을 감지하고 수정합니다. 정확히 무엇이 포함되고 포함되지 않는지는 CAPABILITIES.md를 참조하세요.
처음 오셨나요? GETTING-STARTED.md는 약 5분 만에 설치까지 완료할 수 있도록 안내합니다.
보안 및 개인정보: SECURITY.md(취약점 공개), PRIVACY.md(데이터 유출, 텔레메트리 없음), CAPABILITIES.md(도구가 방어하는 대상과 방어하지 않는 대상)를 참조하세요.
라이선스(소스 사용 가능 — OSI "오픈소스" 아님): 개인 용도로 자유롭게 사용 및 수정할 수 있으며, 영리 목적/회사 내부 사용 및 판매용 제품 구축을 포함합니다. 별도의 유료 라이선스는 소프트웨어 자체를 상업화하는 경우에 만 필요합니다. 즉, 판매, 판매되는 제품이나 서비스에 포함하여 제공, 또는 제3자에게 유료로 기능 제공(호스팅/SaaS/API 포함)하는 경우입니다. 재배포 및 파생물은 라이선스를 유지하고 이 프로젝트를 출처로 표시해야 합니다. LICENSE(상업적 제한은 섹션 4)를 참조하세요. 상업용 라이선스 문의는 github.com/robert-auger를 통해 가능합니다.
**GETTING-STARTED.md**는 약 5분 만에 설치까지 완료할 수 있도록 안내합니다. 필수 조건, 대화형 설치, 검증을 다룹니다. 전체 설치 참조(전역/프로젝트/수동 설치, Windows 관련 사항, 권한 허용 목록, 업데이트, 제거)는 **INSTALLATION.md**를 참조하세요.
일상적인 사용: 훅이 설치되면 실행할 것이 없습니다. safer-dependencies는 백그라운드에서 자동으로 작동합니다. Claude가 패키지를 추가하거나 설치할 때 위험한 종속성을 표시하고 취약한 버전을 안전한 버전으로 그 자리에서 업그레이드하며, 알려진 취약점이 있는 설치는 실행조차 차단하므로 안전하지 않은 패키지는 요청할 필요 없이 감지되고 수정됩니다. 언제든지 직접 호출할 수도 있습니다. "[email protected] 안전해?", "safer-dependencies 설정 확인해줘", "safer-dependencies 통계 보여줘".
Claude가 프로젝트에 패키지를 추가하려고 할 때 safer-dependencies가 가로채어 5가지 검사를 실행합니다.
--hash=sha256:... 고정이 포함된 PyPI requirements.txt 줄의 경우 선언된 해시를 PyPI의 게시된 해시와 대조 검증합니다. 불일치 시 WARNING이 발생합니다paperclip, request, pycrypto, github.com/dgrijalva/jwt-go)는 대체 패키지 제안과 함께 즉시 하드 차단됩니다. 2년 이상 안정 릴리스가 없는 패키지는 권고 수준의 STALE: 경고를 받습니다. 하드 차단된 패키지는 매니페스트에서 제거되고 Claude가 진행 방법을 묻습니다. 오래된(stale) 패키지만 있는 경우는 그대로 둡니다.문제가 발견되면 Claude는 경고를 표시하고 더 안전한 버전으로 물러설 수 있습니다. 모든 검사는 ~/.claude/safer-dependencies-audit-YYYY-MM.log에 기록됩니다(달력 월별 파일 하나).
이 스킬은 다섯 가지 모드로 작동합니다(요약은 아래, 가장 깊은 설계 근거는 skills/safer-dependencies.md에 있음):
Claude가 import를 작성하거나, 매니페스트에 패키지를 추가하거나, 잠금 파일을 업데이트하려고 할 때 스킬이 세션에서 인라인으로 실행됩니다.
버전 선택은 스킬에 번들된 독립형 Python 스크립트가 처리하며, LLM이 규칙을 해석하지 않습니다. 명령은 SELECTED: <version>을 출력하고 Claude는 해당 버전을 정확히 사용합니다.
.claude/settings.json에 PostToolUse 훅을 구성하여 자동으로 투명한 패키지 검증을 활성화합니다.
package.json)을 작성합니다 -- 파일이 디스크에 저장됩니다PostToolUse 훅은 쓰기가 완료된 직후 실행되어 safer-dependencies-shim.sh를 호출합니다hookSpecificOutput.additionalContext를 통해 신호(UPDATED:, BLOCKED:, WARNING:, STALE:, MAJOR-UPDATE-CONFIRM:, REFACTOR-REQUIRED:, REGRESSION:, TYPOSQUAT-CONFIRM:, VERIFY:, )를 출력합니다. 감사 로그에 동일한 (파일, 패키지)가 이전에 동일한 안전 대상으로 수정된 기록이 있으면 앞에 이 옵니다. 즉, 하위 에이전트나 오래된 계획이 알려진 취약 버전을 다시 도입한 것이므로 오케스트레이터는 메이저 업그레이드를 다시 결정하지 않고 이전에 승인된 버전을 복원해야 합니다.설계 참고 — Shape C(쓰기 후 수정): 훅은 쓰기를 차단하지 않습니다. 각 취약 버전은 먼저 디스크에 저장된 후 동일한 툴 사용 주기 내에서 자동 수정됩니다. 이는 PreToolUse 차단 설계보다 의도적으로 선택된 방식입니다. 트레이드오프는 FAQ.md를 참조하세요.
신호 예시:``` UPDATED: aiohttp 3.8.5 → 3.9.0 (HIGH: 33 CVEs fixed)
상위 에이전트는 이러한 신호를 사용하여 영향을 받은 코드를 식별하고 필요에 따라 리팩터링합니다.
### Pre-Install Mode (Bash 훅)
`.claude/settings.json`에 `PreToolUse:Bash` 훅을 구성하여
패키지 관리자 설치 명령에 대한 사전 실행 감사를 활성화합니다. 이는
Intercept Mode를 보완하는 것이지 대체하는 것이 아닙니다 — 함께 계층형 방어를 구성합니다.
1. Claude가 Bash 도구 호출을 시도합니다(예: `npm install [email protected]`)
2. `PreToolUse` 훅이 호출 실행 전에 발동되어
`safer-dependencies-pretooluse-bash.sh`를 호출합니다.
3. 순수 bash 기반의 초기 필터가 약 115 ms 만에 비-PM 명령을 단락 처리합니다
(파이썬 호출 없음). 따라서 `git status` / `ls` / `npm test`는
핫 경로에서 무시할 수 있는 비용만 부담합니다.
4. 인식된 패키지 관리자 설치(`npm`/`pnpm`/`yarn`
`install`/`i`/`add`)의 경우 헬퍼가 `shlex`로 토큰화하여 각
`pkg@version` 인자를 추출한 뒤 OSV에 POST합니다.
5. 취약한 구체적 버전 핀이 있으면 → 훅은
각 발견 항목에 대한 GHSA-id + CVSS + 요약과 함께
`permissionDecision: "deny"`와 safer-dependencies 스킬 호출 힌트를 반환합니다.
6. 설치가 실행되지 않습니다 — 네트워크 가져오기 없음, postinstall 스크립트 실행 없음.
**Intercept Mode 외에 이것이 존재하는 이유:** 사후 쓰기 심은
Bash를 인식하지 못합니다. `npm install [email protected]`은 감사가 발동되기 전에
완료되고(postinstall 스크립트도 실행됨), `npm install -g
typosquat-pkg`는 프로젝트 매니페스트를 전혀 쓰지 않습니다. Pre-Install Mode는
이러한 공백을 구조적으로 메웁니다.
Pre-Install Mode는 사용자가 **입력한** 것(명령줄의 `pkg@version` 인자)만
볼 수 있습니다. 리졸버가 실제로 설치할 전이 의존성 트리는 볼 수 없습니다.
**Post-Install Mode** (아래)는 설치가 완료되면 lockfile을 감사합니다 —
두 모드는 상호 보완적이며 중복이 아닙니다.
**범위:** 여기서 다루는 패키지 관리자 CLI는 다섯 개 에코시스템에 걸쳐 있습니다
(npm/pnpm/yarn/bun/npx/deno, pip/pip3/pipx/pipenv/uv/uvx/poetry, gem/bundle,
go, cargo), Maven은 Intercept Mode를 통해 포함됩니다(Maven 의존성은 일반적으로
`pom.xml`/`build.gradle`에 선언되며 CLI 동사로 추가되지 않습니다).
> **알려진 공백:** Maven CLI는 다음을 통해 직접 다운로드를 지원합니다:
> `mvn dependency:get -Dartifact=group:art:version` 및 `mvn dependency:copy`.
> 이 훅은 아직 이러한 호출을 인식하지 못합니다. 이를 정기적으로 사용한다면,
> 기존 사후 쓰기 심이 매니페스트에 기록되는 내용을 계속 잡아내지만,
> 사전 가져오기 보호는 위에 나열된 에코시스템에만 적용됩니다.
> 후속 작업으로 추적됩니다.
에코시스템별 인식 구문:
| PM | 동사 | 구체적 버전 핀 구문 |
|---|---|---|
| `npm`, `pnpm`, `yarn`, `bun` | `install`, `i`, `add` (추가로 `yarn`/`pnpm dlx`, `bun x`, `yarn create`) | `[email protected]`, `@scope/[email protected]` |
| `npx` | (동사 없음 — 패키지가 첫 번째 위치 인자) | `[email protected]` |
| `deno` | `add`, `install` | `npm:[email protected]` (npm 접두사 사양) |
| `pip`, `pip3`, `pipx`, `pipenv`, `uv`, `uvx`, `poetry` | `install` (pip/pip3/pipx/pipenv) / `add` (uv/poetry) / 동사 없음 (uvx) | `pkg==1.2.3` (extras `pkg[extra]==X`도 처리) |
| `gem`, `bundle` | `install` (gem) / `add` | `-v 1.2.3`, `--version 1.2.3`, `--version=1.2.3` (별도 플래그) |
| `go` | `get`, `install` | `[email protected]` (Go 모듈 규칙에 따라 `v` 접두사 포함 필수) |
| `cargo` | `add`, `install` | `[email protected]` |
범위 핀(npm `^4.17`, pip `>=`, poetry `^`/`~`, Go `@latest`) 및
버전 미지정은 설치 후 Intercept Mode로 전달됩니다 — 사후 쓰기 심은
리졸버가 선택한 값을 감사합니다. 안전한 버전으로의 자동 재작성은
후속 작업으로 예약되어 있습니다.
**실패 모드:** fail-open입니다. 모든 오류(파이썬 누락, 네트워크 일시 장애,
잘못된 입력)는 출력 없이 0으로 종료되어 bash가 계속 진행하도록 합니다.
설치 후에도 Intercept Mode가 계속 실행되므로 사전 실행 실패는
기존 보호로 우아하게 폴백됩니다.
**거부 예시:**```
safer-dependencies pre-flight audit blocked this install.
Vulnerable pinned version(s) detected:
- [email protected] → GHSA-35jh-r3h4-6jhm (CVSS:7.4): Command Injection in lodash
Re-run with a patched version, or invoke the safer-dependencies skill
for a recommended pin.
.claude/settings.json에 PostToolUse:Bash 훅을 구성하면 Bash 명령 후 사후 감사를
활성화할 수 있습니다. 이 훅은 명령의 cwd를 대상으로 세 가지 독립적 스캔을 실행하며,
각 스캔은 다른 훅으로는 해결할 수 없는 공백을 메웁니다.
npm install,
bundle install, poetry install, uv sync, go mod tidy 등) 후 방금 수정된
lockfile(package-lock.json, Gemfile.lock,
poetry.lock, uv.lock, go.sum, yarn.lock, pnpm-lock.yaml,
Pipfile.lock)을 감사합니다. 이는 Pre-Install이 볼 수 없는 전이 CVE 격차를
해소합니다. 사용자는 pkg@version을 입력했지만, 의존성 해석기는
아무도 명명하지 않은 수십 개의 전이 의존성을 끌어들였을 수 있습니다.스캔 실행 방식:
PostToolUse 훅은 명령 완료 후에 실행되며
safer-dependencies-posttooluse-bash.sh를 호출합니다ls / git / cat이
지불하는 비용은 무시할 수 있습니다find -maxdepth 5로 cwd를 탐색합니다(모노레포 레이아웃 포함;
node_modules, .git, .venv, venv 제외). 마지막 60초 이내에 수정된 파일을 대상으로
합니다 — SAFE_DEP_POSTINSTALL_MTIME_WINDOW로 재정의 가능PostToolUse:Write 페이로드를 만들어 기존 shim으로 파이프합니다. shim의
lockfile 및 manifest 감사자는 변경 없이 실행되며 로직이 중복되지 않습니다Pre-Install이 잡아내지 못하는 것: 전이 의존성 취약점.
깔끔해 보이는 bundle install은 sinatra의 전이 의존성으로
[email protected](CVE-2025-27610)을 끌어들일 수 있습니다. 사용자는 rack을 입력한 적이 없으므로
Pre-Install은 이를 볼 수 없지만, Post-Install은 해석된
Gemfile.lock을 읽고 CVE를 보고합니다.
범위: Scan A는 해석된 버전을 다시 쓰지 않습니다. 자동 수정
계약은 Claude가 직접 작성한 manifest에만 적용됩니다. 전이 CVE의 경우
일반적인 수정은 "해당 전이 의존성을 소유한 직접 의존성을 업데이트"하는 것이며,
사람의 판단이 필요합니다. Scan B는 Intercept 모드와 동일한 shim 경로로 manifest를 감사하므로
자동 수정을 수행합니다. Scan A는
transitive 검사 등급이 off로 설정된 경우(config set checks.transitive off) 건너뜁니다.
실패 모드: 다른 훅과 마찬가지로 fail-open입니다. 어떤 오류(shim 누락, 잘못된 페이로드, Python 사용 불가)가 발생해도 조용히 0으로 종료됩니다.
예시 경고:``` WARNING: [email protected] in lock file has GHSA-29mw-wpgm-hmr9, GHSA-35jh-r3h4-6jhm
### Post-Agent 모드 (Agent 훅 쌍)
위의 네 가지 모드는 **루트 세션** 도구 호출에서만 발동합니다. 루트 세션이 하위 에이전트를 파견하면(`Agent` 도구를 통해 — 많은 스킬과 슬래시 명령이 내부적으로 이 작업을 수행합니다), 하위 에이전트의 Write/Edit/Bash 호출은 이 모두를 우회합니다. Post-Agent 모드는 이러한 공백을 메우는 사후 대응형 안전망입니다.
1. `PreToolUse:Agent` 훅(`safer-dependencies-pretooluse-agent.sh`)은 각 Agent 파견 직전에 실행되어 `/tmp/.safer-deps-agent-<PPID>-<session_id>.sentinel`에 센티널 파일을 생성합니다(세션 ID가 없으면 PPID만 포함된 이름으로 대체).
2. 하위 에이전트가 실행되며 매니페스트나 잠금 파일을 작성할 수 있습니다.
3. `PostToolUse:Agent` 훅(`safer-dependencies-posttooluse-agent.sh`)은 Agent 호출이 반환된 후 실행되어 센티널보다 새로운 모든 매니페스트와 잠금 파일을 `find`로 찾아내고, 동일한 shim 경로를 통해 각각을 감사합니다.
4. 발견 사항은 루트 세션의 다음 턴에 `additionalContext`로 표시되며, 센티널은 제거됩니다.
중첩 하위 에이전트는 자동으로 처리됩니다 — 루트의 `PostToolUse:Agent`는 외부 에이전트의 모든 작업(해당 에이전트가 파견한 모든 것 포함)이 디스크에 기록된 후에만 발동합니다. 유일한 공백은 매니페스트나 잠금 파일을 작성하지 않는 전역 설치(`npm install -g …`)입니다. 스캔할 대상이 없기 때문입니다. 다른 훅과 마찬가지로 fail-open 방식입니다 — 어떤 오류(센티널 누락, shim 누락, 읽을 수 없는 페이로드)든 조용히 0으로 종료됩니다. 전체 설계 근거는 `skills/safer-dependencies.md`에 있습니다.
## 무엇이 발동시키나
이 스킬은 Claude가 다음 작업을 수행할 때 자동으로 발동합니다:
**매니페스트 / 설치 작업**
- `package.json`, `requirements.txt`, `Gemfile`, `pom.xml`, `build.gradle`, `Cargo.toml`, `go.mod` 또는 기타 지원되는 매니페스트에 패키지를 추가하거나 업데이트하는 경우
- 매니페스트에 아직 선언되지 않은 패키지에 대한 `import`, `require` 또는 `use`를 작성하는 경우
- 잠금 파일을 생성하거나 업데이트하는 경우(새 항목/변경 항목만 검사)
- Bash를 통해 패키지 관리자 설치를 실행하는 경우(`npm install`, `bundle install`, `poetry install`, `uv sync`, `go mod tidy` 등) — Pre-Install은 명령 인수를 감사하고, Post-Install은 결과 잠금 파일을 감사합니다
- 고정된 패키지 관리자 설치 단계를 포함하는 `Dockerfile` 또는 CI 워크플로(`.github/workflows/*.yml` 등)를 작성하는 경우
**선택 및 추천 질문**
- 라이브러리/프레임워크 비교: "axios 또는 node-fetch 중 무엇을 사용해야 하나요?", "moment vs dayjs?", "X와 Y 중 어떤 것이 더 나은가요?"
- 추천 요청: "Python용 좋은 HTTP 클라이언트는 무엇인가요?", "Go용 로깅 라이브러리를 추천해 주세요", "Node에서 CSV를 처리하는 패키지는 무엇인가요?"
- 버전 선택: "Django는 어떤 버전을 사용해야 하나요?", "최신 안정 버전 Flask?"
**사용 의도 표현(추가 전)**
- "이 프로젝트에 FastAPI를 사용하고 싶어요", "Celery를 추가할까 생각 중이에요", "ORM으로 Prisma를 검토하고 있어요", "Tailwind를 사용하자"
**패키지 상태 및 신뢰 질문**
- "moment.js는 아직 유지보수되고 있나요?", "이 gem은 아직 활성 상태인가요?", "X는 버려졌나요?", "X는 EOL인가요?", "이 패키지를 신뢰해도 되나요?", "faker는 언제 마지막으로 업데이트되었나요?"
**스캐폴딩 명령**
- `npx create-react-app`, `npm create vite@latest`, `django-admin startproject`, `rails new`, `cargo new` + `cargo add`, "새 FastAPI 프로젝트 부트스트랩해 줘"
**암시적 패키지 추가(새 종속성을 암시하는 기능 요청)**
- "앱에 Redis 캐싱을 추가해 줘", "Postgres에 연결해 줘", "JWT 인증을 추가해 줘", "이메일을 보내는 코드를 작성해 줘" — 해당 기능을 위한 패키지가 아직 매니페스트에 없을 때 발동합니다
**마이그레이션 및 포팅**
- "requests에서 httpx로 마이그레이션해 줘", "CRA에서 Vite로 이동해 줘", "moment에서 date-fns로 포팅해 줘" — 새로 도입되는 패키지를 감사합니다
다음 경우에는 **발동하지 않습니다**:
- 표준 라이브러리 임포트(`os`, `fs`, `java.util.*` 등)
- 변경되지 않는 이미 선언된 종속성
- 패키지가 내부적으로 어떻게 동작하는지에 대한 학술적 논의("React의 reconciler를 설명해 줘", "webpack의 모듈 해석은 어떻게 동작하나요?") — 비교 및 선택 질문은 여전히 발동합니다
- OS 수준 앱, 런타임 또는 IDE 확장 설치(Python 자체, Docker, Homebrew, VS Code 확장)
## 이 저장소의 구성
이것은 단일 스킬 파일이 아닌 **스킬 + 훅 번들**입니다. 완전한 설치는 다음 구성 요소를 배포합니다:
| File | Role |
|---|---|
| `skills/safer-dependencies.md` | **스킬**(설치 시 `SKILL.md`가 됨). 감사 절차를 설명하며 설치/통계용 관리 모드를 포함합니다. |
| `skills/safer-dependencies-shim.sh` | `PostToolUse:Write`/`Edit` 훅 — 매니페스트 + 잠금 파일 쓰기를 감사하고 취약한 버전을 제자리에서 자동 수정합니다(Intercept 모드). |
| `skills/safer-dependencies-pretooluse-bash.sh` | `PreToolUse:Bash` 훅 — 패키지 관리자 설치 명령에 대한 사전 OSV 감사; 설치가 실행되기 전에 취약한 버전으로 고정된 패키지를 거부합니다(Pre-Install 모드). |
| `skills/safer-dependencies-posttooluse-bash.sh` | `PostToolUse:Bash` 훅 — Bash 명령 후 사후 감사; 새로 작성된 잠금 파일, `sed`/`jq`/스크립트로 편집된 매니페스트, 일반 `pip install`의 의존성 해석 결과 환경에서 전이적 CVE를 포착합니다(Post-Install 모드). |
| `skills/safer-dependencies-pretooluse-agent.sh` + `skills/safer-dependencies-posttooluse-agent.sh` | `PreToolUse:Agent` + `PostToolUse:Agent` 훅 쌍 — 하위 에이전트 커버리지 공백을 해소합니다. 모드 2–4는 루트 세션 도구 호출에서만 발동하므로 하위 에이전트가 작성하는 모든 매니페스트는 이를 우회합니다. Post-Agent는 각 Agent 도구 호출이 반환된 후 하위 에이전트가 작성한 모든 것을 감사합니다(Post-Agent 모드). |
| `skills/scripts/` | 모든 훅이 사용하는 공유 Python 라이브러리(`safedep/`) 및 독립형 리졸버 스크립트. |
| `skills/scripts/safer_dependencies_manager.py` | 대화형 설치, 사용 통계 및 설정 검증을 위한 관리 모듈. |
스킬 파일만으로는 충분하지 않습니다 — 훅이 없으면 자동 호출은 Claude가 스킬을 사용하기로 결정하는 데 달려 있습니다. 전체 커버리지를 위해 다섯 구성 요소를 모두 설치하세요. 많은 스킬과 슬래시 명령이 내부적으로 하위 에이전트를 파견하므로, 직접 명시적으로 하나도 생성하지 않더라도 Post-Agent 쌍이 중요합니다. (스킬 단독으로는 커버리지를 보장할 수 없는 이유는 [FAQ.md](https://github.com/robert-auger/safer-dependencies/blob/HEAD/FAQ.md#why-a-skill-alone-is-not-sufficient)를 참조하세요.)
## 지원되는 에코시스템
| 에코시스템 | 매니페스트 | 잠금 파일 |
|-----------|----------|-----------|
| npm | `package.json` | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` |
| PyPI | `requirements.txt`, `pyproject.toml`, `Pipfile`, `setup.py`, `setup.cfg` | `Pipfile.lock`, `poetry.lock`, `uv.lock` |
| RubyGems | `Gemfile`, `*.gemspec` | `Gemfile.lock` |
| Maven | `pom.xml`, `build.gradle`, `libs.versions.toml` | -- |
| Go | `go.mod` | `go.sum` |
| Rust | `Cargo.toml` | `Cargo.lock` |
| PHP (Composer) | `composer.json` | `composer.lock` |
## 설치
프로젝트가 처음이신가요? **[GETTING-STARTED.md](https://github.com/robert-auger/safer-dependencies/blob/HEAD/GETTING-STARTED.md)**부터 시작하세요. 간단히 요약하면:```bash
git clone https://github.com/robert-auger/safer-dependencies /tmp/safer-dependencies
python3 /tmp/safer-dependencies/skills/scripts/safer_dependencies_manager.py interactive_install
설치 프로그램이 범위(전역 vs 프로젝트)와 활성화할 훅을 묻고, settings.json을 직접 작성해 줍니다 — 훅 항목 및 스킬의 검사 명령이 매 감사 때마다 승인 프롬프트 없이 실행되도록 하는 권한 허용 목록까지 포함합니다.
설치와 관련된 나머지 모든 내용은 **INSTALLATION.md**에 있습니다. 이 문서가 설치 메커니즘의 단일 참조 자료입니다: 수동 파일별 설치(전역 및 프로젝트 수준), Windows 관련 세부 사항, Post-Agent 훅, 권한 허용 목록, 설정 확인, 업데이트, 릴리스 태그 고정, 제거.
설치 후 일상적인 관리는 자연어로 Claude에게 지시하는 방식 — install safer-dependencies(재실행/훅 변경), show safer-dependencies stats, check safer-dependencies setup — 또는 /safer-dependencies 메뉴로 수행할 수 있습니다. 업데이트 역시 세션 내에서 가능합니다: /safer-dependencies update가 최신 릴리스를 적용합니다(update --check는 dry-run, update --rollback은 되돌리기). 신뢰 모델은 INSTALLATION.md를 참조하세요.
플랫폼 참고: macOS, Linux, Windows를 지원합니다. Windows는 Git for Windows(bash 제공)와
PATH에 Python 3이 필요합니다 — WSL은 필요 없습니다. 지금까지의 실사용 테스트는 macOS와 Windows에 집중되었으며, Linux 지원은 자동화된 CI 매트릭스로 검증됩니다.
설치 후 구성할 수 있는 항목은 두 가지입니다:
npm audit / bundle audit 규칙과 스킬 자체 리졸버 스크립트)을 사전 승인하여 매번 승인 프롬프트 없이 감사가 실행되도록 합니다. curl은 절대 사전 승인되지 않으며, npm view / pip-audit은 Convenience 프로필을 통해 선택적으로 활성화됩니다. 대화형 설치 프로그램이 핵심 항목을 직접 작성해 주고, 수동 설치는 전체 블록을 직접 추가합니다. 전체 블록 및 근거: INSTALLATION.md → Permissions allowlist.off/warn/block 등급. /safer-dependencies config로 편집하며 ~/.config/safer-dependencies/config.toml에 저장됩니다. 스키마 및 등급 의미론: skills/references/configuration.md.모든 검사는 ~/.claude/safer-dependencies-audit-YYYY-MM.log에 단일 JSON 줄로 기록됩니다(달력 월별 파일 1개, YYYY-MM은 UTC 연-월). SAFE_DEP_AUDIT_LOG 환경 변수로 전체 경로를 재정의할 수 있습니다(설정하면 날짜 접미사가 추가되지 않습니다). 파일은 SAFE_DEP_LOG_MAX_BYTES를 초과하면 크기 기준으로 순환됩니다(기본값 10 MiB, 0으로 설정하면 비활성화). SAFE_DEP_MODEL을 설정하면 각 항목의 source.model에 기록되는 모델 값을 재정의할 수 있습니다 — 모델 버전 간 A/B 비교에 유용합니다.
다섯 가지 모드 모두 동일한 파일에 추가됩니다. 각 항목은 해당 항목을 기록한 구성 요소를 식별하는 source 블록(스키마 2.2)을 포함합니다:
source.model은 세션에서 활성화된 Claude Code 모델(예: "claude-sonnet-4-6")을 기록합니다. 스키마 2.1+에 포함되며, 이전 설치로 작성된 항목에는 이 필드가 없습니다. stats 명령은 이 필드가 없으면 "unknown"으로 우아하게 처리됩니다.
jq를 사용해 source.component로 필터링:```bash
jq -r '.source.component' audit.log | sort | uniq -c | sort -rn
jq -c 'select(.source.component == "bash.pretooluse")' audit.log
jq -c 'select(.source.mode == "fail_open") | {component: .source.component, reason: .fail_open.reason, ts}' audit.log
보다 쉬운 분석을 위해 로그를 수동으로 파싱하는 대신 Claude에게 사용 통계를 요청하세요:```
"Show safer-dependencies stats for the last month"
이는 이러한 감사 로그에서 추출된 활동, 보안 영향, 성능 지표에 대한 사람이 읽을 수 있는 요약을 제공합니다.
항목 형태 (스키마 2.2). 세 가지 서로 다른 형태가 동일한 ts / schema / source 헤더를 공유합니다:
감사 항목: 차단(Intercept) 모드는 전체 파이프라인(출처, 버전 연식, OSV, 중단/오래됨, 유사 패키지(typosquat), 서명)을 실행하므로 모든 배열이 채워질 수 있습니다. 사전 설치(Pre-Install) 모드는 현재 OSV만 실행하므로 abandoned / stale / typosquat / signatures는 항상 비어 있습니다. 사후 설치 디스패치(잠금 파일 감사)는 shim.posttooluse 아래에 기록하며 findings는 잠금 파일 감사기의 WARNING: 문자열로 채워집니다. notes 배열은 정보성 NOTE: 신호(예: 고정되지 않아 매니페스트 건너뜀)를 담습니다.
스키마 2.2는 잠금 파일 감사 항목에 네 개의 필드를 추가적으로(비파괴적으로) 추가했습니다: lockfile, manifest_ref, relation_summary(플래그된 각 패키지를 형제 매니페스트에 대해 직접/간접/알 수 없음으로 분류) 및 시행 중인 transitive 등급을 기록하는 policy 블록. 이 변경은 하위 호환됩니다: 2.1 항목을 읽는 쪽은 새 필드를 허용하며, source.model 필드는 2.1부터 계속 존재합니다.```json
{
"ts": "2026-04-19T12:34:56Z",
"schema": "2.2",
"source": {
"component": "shim.posttooluse",
"script": "shim.sh",
"hook": "PostToolUse:Write",
"tool": "Write",
"mode": "intercept",
"model": "claude-sonnet-4-6"
},
"file": "/path/to/project/package.json",
"ecosystem": "npm",
"checked": ["[email protected]", "[email protected]"],
"findings": ["UPDATED: express 4.18.2 → 4.22.1 (HIGH: 1 CVE fixed)"],
"abandoned": [],
"stale": [],
"typosquat": [],
"unknown": [],
"signatures": [],
"notes": [],
"clean": ["[email protected]"]
}
Pre-Install Mode example (Bash hook, vulnerable pin denied):```json
{
"ts": "2026-04-23T06:56:21Z",
"schema": "2.2",
"source": {
"component": "bash.pretooluse",
"script": "pretooluse-bash.sh",
"hook": "PreToolUse:Bash",
"tool": "Bash",
"mode": "intercept",
"model": "claude-sonnet-4-6"
},
"file": "bash:npm install [email protected] [email protected]",
"ecosystem": "npm",
"checked": ["[email protected]", "[email protected]"],
"findings": [
"BLOCKED: [email protected] GHSA-35jh-r3h4-6jhm (CVSS:3.1/...): Command Injection in lodash"
],
"abandoned": [],
"stale": [],
"typosquat": [],
"unknown": [],
"signatures": [],
"notes": [],
"clean": ["[email protected]"]
}
Fail-open Mode 예시 (설치 후 Bash 훅이 인접한 shim 없이 호출됨 — 손상된 설치):```json { "ts": "2026-05-03T07:14:11Z", "schema": "2.2", "source": { "component": "bash.posttooluse", "script": "safer-dependencies-posttooluse-bash.sh", "hook": "PostToolUse", "tool": "Bash", "mode": "fail_open", "model": "claude-sonnet-4-6" }, "fail_open": { "reason": "shim_missing", "detail": "/home/alice/.claude/skills/safer-dependencies" } }
A fail-open 항목은 "이 훅이 실행되었지만 필수 조건이 누락되어 감사(audit)를 수행하지 않고 조기 종료되었습니다"를 의미합니다. 위의 jq 필터(`select(.source.mode == "fail_open")`)를 사용하여 로그에서 모든 무음 보호 손실 이벤트를 표시하십시오.
shim이 dry-run 모드(`SAFE_DEP_DRY_RUN=1`)로 실행되면 항목에는 `"mode": "dry_run"`도 포함되므로 사후 분석에서 감사 전용 호출을 필터링할 수 있습니다.
## 요구 사항
- Python 3.9+ (훅이 이를 확인하며 이전 버전 인터프리터에서는 fail-open 처리됨)
- `curl` (레지스트리 API 호출 및 OSV 취약점 확인용)
- 에코시스템 도구(선택 사항, 없으면 스킬이 OSV API로 대체):
- `npm` (npm 패키지용)
- `pip-audit` (Python 패키지용)
- `bundle` (Ruby 패키지용)
- `dependency-check` (Java 패키지용)
## FAQ
설계 결정 근거(`PostToolUse` 대신 `PreToolUse`를 사용하는 이유, 서명이 검증되지 않는 이유, 스크립트와 shim이 중복되는 이유, 스킬 로딩 문제 등)는 [`FAQ.md`](https://github.com/robert-auger/safer-dependencies/blob/HEAD/FAQ.md)에 문서화되어 있습니다.
CLEAN:MAJOR-UPDATE-CONFIRM:REGRESSION:ls, cat, git status, …)에
없는 Bash 명령 후에는 방금 수정된 manifest를 감사합니다.
이는 sed -i, jq 또는 스크립트를 통한 manifest 편집에 대한 유일한 폴백입니다.
그러한 편집은 Intercept 모드가 훅하는 Write/Edit 도구를 우회합니다.pip install /
pip install -r requirements.txt는 lockfile을 작성하지 않으므로 Scan A는
해석된 트리를 볼 수 없습니다. pip 형태의 설치 후 Scan C는 동일한
pip를 읽기 전용 list --format=json으로 다시 호출하고 전체 해석된
환경(직접 + 전이)을 OSV 검사합니다.hookSpecificOutput
JSON으로 상위 에이전트에 전달됩니다| 수준 |
|---|
| 의미 |
|---|
| 예 |
|---|
| CRITICAL | 중지하고 사용자에게 확인 | 타이포스쿼트 감지, 변조된 서명 |
| HIGH | 경고 후 계속 진행 | 알려진 CVE, 출시 30일 미만 패키지 |
| MEDIUM | 경고 후 계속 진행 | 출시 7일 미만 버전, 서명 누락 |
| LOW | 경고 후 계속 진행 | 서명 없는 Ruby gem(예상됨) |
source.component | 작성 주체 | 트리거 |
|---|
shim.posttooluse | shim.sh | 매니페스트 또는 잠금 파일 쓰기(Intercept Mode, Post-Install 디스패치) |
shim.install_error | shim.sh | Shim 사전 점검 설치 실패 |
bash.pretooluse | pretooluse-bash.sh | Bash 설치 명령(Pre-Install Mode) |
bash.posttooluse | posttooluse-bash.sh | Post-Install Bash 훅 자체가 shim에 도달하기 전에 fail-open되는 경우 |
agent.pretooluse | pretooluse-agent.sh | Pre-Agent fail-open 이벤트용 예약(훅 자체는 현재 성공 시 아무것도 기록하지 않음) |
agent.posttooluse | posttooluse-agent.sh | Post-Agent 훅 fail-open 이벤트(예: shim 누락, python_missing) |
manual.skill | Normal Mode로 실행되는 Claude | 인라인으로 호출된 수동 감사 |
| 형태 | 기록 시점 | 구분 필드 |
|---|
| 감사 항목 | 매니페스트 / 잠금 파일 / bash 설치 감사 | file, ecosystem, checked, findings, abandoned, stale, typosquat, unknown, signatures, notes, clean |
| 설치 오류 항목 | 심(shim) 사전 점검 설치 오류 (구성 요소 shim.install_error) | install_error, shim_dir, scripts_dir |
| 장애 허용(fail-open) 항목 | helper_missing / shim_missing / python_missing 때문에 모든 후크 진입점이 조기 종료됨. source.mode는 "fail_open" | fail_open: { reason, detail? } |