Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
sloppy-joe — 공급망, slopsquatting, typosquatting 공격으로부터 의존성과 코드를 보호합니다. | Kitploit
도구/GitHubGitHub/brennhill/sloppy-joe
Static AnalysisVulnerability ScannersCode AnalysisDevSecOpsSecret DetectionThreat IntelligenceSupply Chain SecurityLearning & Education
GitHubbrennhill/sloppy-joe

sloppy-joe

공급망, slopsquatting, typosquatting 공격으로부터 의존성과 코드를 보호합니다.

저장소 보기
32134개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

sloppy-joe

환각(hallucination)된, 오타스쿼팅된, 비정규 의존성을
프로덕션에 도달하기 전에 잡아내세요.

cargo install sloppy-joe


2026년 3월의 LiteLLM 공급망 공격은 월간 9700만 다운로드의 패키지를 손상시켰습니다. 공격자는 배포 자격 증명을 탈취하고, SSH 키, 클라우드 자격 증명, K8s 비밀을 수집하는 악성 버전을 푸시했습니다. sloppy-joe의 기본 72시간 버전 연령 게이트는 두 개의 감염된 버전을 모두 차단했을 것입니다. 이들은 게이트가 열리기 훨씬 전인 몇 시간 이내에 발견되었습니다. CI에서 sloppy-joe check를 실행하면 이 공격은 실패합니다. 전체 분석

AI 코드 생성기는 약 20%의 확률로 패키지 이름을 환각합니다. 공격자는 그 이름들을 등록하고 기다립니다. sloppy-joe는 npm install 또는 pip install이 실행되기 전에 CI에서 이를 잡아냅니다.

사용 방법```bash

Install (single static binary, no runtime dependencies)

cargo install sloppy-joe

Or download an auditable binary archive from GitHub Releases

https://github.com/brennhill/sloppy-joe/releases

Fast local guardrail — auto-detects ecosystem from manifest files

sloppy-joe check

Strict online scan (recommended before push / release)

sloppy-joe check --full

Strict CI-oriented scan

sloppy-joe check --ci

Check a specific directory

sloppy-joe check --dir ./my-project

Check only npm dependencies

sloppy-joe check --type npm

Check the Python runtime plus selected groups/extras

sloppy-joe check --python-groups dev,test --python-version 3.12 sloppy-joe check --python-extras docs --python-platform linux --python-version 3.12

Enforce canonical rules and org standards via config

sloppy-joe check --config /etc/sloppy-joe/config.json

Config from a URL (useful in CI — no secrets to manage)

sloppy-joe check --config https://raw.githubusercontent.com/yourorg/security-configs/main/sloppy-joe.json

JSON output for CI pipelines

sloppy-joe check --json

Review exact maintainer-change exceptions with evidence

sloppy-joe check --review-exceptions

Create and register a safe per-repo config outside the repo

sloppy-joe init --register

Create an ecosystem-specific greenfield starter policy

sloppy-joe init --greenfield --ecosystem npm

Print review-only bootstrap suggestions for an npm or Cargo repo

sloppy-joe init --from-current

Or write/register those suggestions safely outside the repo

sloppy-joe init --from-current --register

Or write a config manually to a secure path outside the repo

sloppy-joe init > /secure/location/sloppy-joe.json

root@kitploit:~
### Nix```bash
nix profile install github:brennhill/sloppy-joe

스캔 모드:

  • sloppy-joe check는 빠른 로컬 가드레일을 실행합니다. 항상 매니페스트 파싱, lockfile/동기화, 출처 증명, 지원되지 않는 소스 정책을 적용합니다. 종속성 또는 정책 상태가 변경되었거나 마지막 성공적인 전체 스캔이 24시간보다 오래된 경우 sloppy-joe check --full을 권장합니다.
  • sloppy-joe check --full은 엄격한 온라인 스캔을 실행하고 기록된 성공적인 전체 스캔 상태를 새로고침합니다.
  • sloppy-joe check --ci는 --full과 동일한 엄격한 적용 범위를 CI 지향 목적으로 실행합니다.
  • Python의 경우 sloppy-joe check는 기본적으로 runtime 프로필을 평가합니다. 범위가 지정된 종속성이 있으면 경고를 표시하고 CI/빌드 패리티를 위해 명시적 --python-groups, --python-extras, --python-platform 및/또는 --python-version 플래그를 전달하도록 안내합니다.
  • 사람이 읽을 수 있는 일반 sloppy-joe check 출력은 항상 CI 및 프로덕션 게이팅에 --ci 또는 --full을 사용하라고 알립니다.

종료 코드: 0 = 선택한 모드에서 차단 문제 없음, 1 = 차단 문제 발견, 2 = 런타임 오류.

지원 대상: JavaScript (npm, pnpm, Yarn, Bun), Python, Rust, Go, Ruby, PHP, JVM (Gradle/Maven), .NET — 매니페스트 파일에서 자동 감지.

에코시스템 가이드: 각 에코시스템의 현재 신뢰 모델, 지원 기능, fail-closed 제한에 대한 자세한 내용은 docs/ecosystems/README.md를 참조하세요.

  • JavaScript
  • Python
  • Rust
  • Go
  • Ruby
  • PHP / Composer
  • JVM
  • .NET / NuGet
에코시스템필수 매니페스트신뢰하는 lockfile / 프로젝트 상태
JavaScript / npmpackage.jsonpackage-lock.json 또는 npm-shrinkwrap.json; 레거시 npm v1은 기본적으로 차단됨
JavaScript / pnpmpackage.jsonpnpm-lock.yaml
JavaScript / Yarnpackage.jsonyarn.lock
JavaScript / Bunpackage.jsonbun.lock
Pythonpyproject.toml, requirements*.txt, Pipfile, setup.cfg 또는 setup.py신뢰하는 Poetry 경로는 poetry.lock 사용, 신뢰하는 uv 경로는 uv.lock 사용, 완전 해시 잠금된 pip-tools는 커밋된 요구사항 그래프가 --index-url과 모든 --extra-index-url 값을 정확히 바인딩할 때만 신뢰됨; 저장소에 표시되는 Python 인덱스는 trusted_indexes.pypi를 통해 허용 목록에 추가 가능; 신뢰하는 Python 모드는 한 번에 선택된 하나의 설치 프로필을 평가함(기본값 runtime, 명시적 groups/extras/platform/arch/version은 CLI를 통해 전달); 레거시 매니페스트는 기본적으로 경고와 함께 허용됨
RustCargo.tomlCargo.lock
Gogo.mod외부 종속성을 위해 go.sum 필요
RubyGemfileGemfile.lock
PHP / Composercomposer.jsoncomposer.lock
JVM / Gradlebuild.gradle 또는 build.gradle.ktsgradle.lockfile
JVM / Mavenpom.xml경고 전용: 아직 신뢰할 수 있는 프로젝트 로컬 lockfile 경로 없음
.NET / NuGet.csprojpackages.lock.json

설정 소스: 로컬 파일 경로, HTTPS URL 또는 SLOPPY_JOE_CONFIG 환경 변수. 설정은 프로젝트 디렉터리에서 읽지 않습니다(이유는 CONFIG.md 참조).

온보딩: 저장소와 일치하는 부트스트랩 모드를 사용하세요.

  • sloppy-joe init --greenfield --ecosystem <eco>는 새 프로젝트를 위한 에코시스템별 시작 정책을 출력합니다. 현재 npm, pypi, cargo에 대해 그린필드 프리셋이 구현되어 있습니다. 다른 에코시스템은 "아직 지원되지 않음" 오류와 함께 실패합니다. --register를 추가하면 저장소 외부에 쓰고 안전하게 등록합니다.
  • sloppy-joe init --from-current는 현재 저장소를 검사하고 검토 전용 부트스트랩 제안을 출력합니다. 현재 --from-current는 first-party 코드가 npm 및/또는 cargo인 저장소에서만 구현되어 있으며, 다른 에코시스템은 "아직 구현되지 않음" 오류와 함께 fail-closed됩니다. --register를 추가하면 생성된 설정을 쓰고 등록합니다.
  • 모드 없이 sloppy-joe init을 실행하면 중립적인 수동 템플릿이 출력됩니다.

sloppy-joe를 사용하는 이유?

단일 바이너리. 8개 에코시스템. 16가지 공격 유형. 생성적 검사에서 거짓 긍정 없음. AI 에이전트가 변조할 수 없는 설정.

대부분의 종속성 보안 도구는 한두 가지만 확인합니다. 존재 여부 또는 편집 거리입니다. sloppy-joe는 한 번의 패스로 16가지 공격 벡터를 확인합니다: 존재하지 않는 패키지, 10가지 유형의 타이포스쿼팅(호모글리프, 범위 스쿼팅, 문자 반복, 구분자 혼동, 단어 재배열, 인접 스왑, 문자 생략, 혼동된 형태, 대소문자 변형, 버전 접미사), 표준 적용, 버전 연령 게이트, 설치 스크립트 증폭, 종속성 폭발, 유지 관리자 변경, OSV.dev를 통한 알려진 취약점.

단일 Rust 바이너리로 실행되며 런타임 종속성이 없습니다. 모든 8개 주요 패키지 에코시스템을 지원합니다. 그리고 설정은 보안을 위해 설계되었습니다: 프로젝트 디렉터리에서 읽지 않으며, CI를 위해 URL에서 로드 가능하며, 문제가 있을 때 명확한 오류 메시지를 제공합니다.

sloppy-joeSocket.devGuardDogPhantom Guardantislopsquat
존재 확인✅✅❌✅✅
유사성 / 타이포스쿼트✅✅✅✅❌
호모글리프 탐지✅❌❌❌❌
범위 스쿼팅✅❌❌❌❌
표준 적용✅❌❌❌❌
버전 연령 게이트✅❌❌❌❌
설치 스크립트 증폭기✅✅❌❌❌
종속성 폭발✅❌❌❌❌
유지 관리자 변경✅✅❌❌❌
OSV 취약점 확인✅✅❌❌❌
설정 보안 (저장소 외부)✅N/A❌❌❌
내부 + 허용 목록✅❌❌

🔶 = 베타/실험적


각 공격의 작동 방식 (그리고 sloppy-joe가 이를 차단하는 방법)

1. 존재하지 않는 패키지 (Hallucinated packages)

공격: AI가 import ai_json_helper를 생성합니다. 패키지가 존재하지 않습니다. 공격자가 PyPI에 ai-json-helper라는 악성 패키지를 등록합니다. 다음 번에 누군가 pip install을 실행하면 악성 패키지를 설치하게 됩니다.

sloppy-joe가 차단하는 방법: 존재 확인이 PyPI API에 접근하여 404를 받습니다. 빌드가 차단됩니다.``` ERROR ai-json-helper [existence] Package 'ai-json-helper' does not exist on the pypi registry. It may be hallucinated by an AI code generator. Fix: Remove 'ai-json-helper' from your dependencies.

root@kitploit:~
### 2. 타이포스쿼팅 (생성적 검사 + 편집 거리 대체)

**공격:** 공격자가 `expresz`를 npm에 등록합니다. 이것은 `express`에서 한 글자가 변경된 것입니다. AI가 생성하거나 개발자가 오타를 냅니다. 이 패키지는 존재하며, 존재 여부 검사를 통과하고 맬웨어를 설치합니다.

**sloppy-joe가 이를 차단하는 방법:** sloppy-joe는 편집 거리로 대체되기 전에 10개의 생성적 검사를 실행합니다. 각 생성적 검사는 종속성 이름의 특정 변형을 생성합니다 (문자 교환, 반복 축소, 접미사 제거, 단어 재정렬, 구분자 정규화, 호모글리프 대체, 스코프 확인) 그리고 알려진 인기 패키지와 정확히 일치하는지 테스트합니다. 이 접근 방식은 [Rust Foundation의 Typomania](https://github.com/rustfoundation/typomania) 라이브러리에서 영감을 받았으며, 변형 후 정확히 일치하는 경우에만 작동하므로 오탐이 거의 없습니다.

Levenshtein 편집 거리는 특정 검사에서 예상하지 못한 새로운 변형에 대한 안전망으로 마지막에 실행됩니다. 이들은 함께 알려진 공격 패턴(정확히)과 알려지지 않은 패턴(광범위하게)을 모두 커버합니다.```
ERROR expresz [similarity/edit-distance]
      'expresz' is 1 character away from 'express'. This could be a typosquat.
 Fix: If you meant 'express', fix the name in your manifest.

3. 반복된 문자

공격: expresss (s 중복) 또는 reeact (e 중복). 이는 일반적인 AI 환각 패턴입니다 — 모델이 반복 문자를 포함한 그럴듯한 이름을 생성합니다.

sloppy-joe가 차단하는 방법: 반복 문자 검사는 한 번에 하나의 중복을 제거하고 결과가 알려진 패키지와 일치하는지 확인합니다. expresss → s 하나 제거 → express → 일치.``` ERROR expresss [similarity/repeated-chars] 'expresss' matches 'express' after removing a repeated character. Fix: Use 'express' — remove the repeated characters.

root@kitploit:~
### 4. 구분자 혼동

**공격:** `python-dateutil` 대 `python_dateutil` 대 `pythondateutil`. 일부 레지스트리에서는 이들이 서로 다른 패키지입니다. 공격자가 변형을 등록합니다.

**sloppy-joe가 차단하는 방법:** 비교 전에 모든 구분자(`-`, `_`, `.`)를 정규화합니다. 정규화된 형태가 알려진 패키지와 일치하면 플래그가 지정됩니다.```
ERROR socket_io [similarity/separator-confusion]
      'socket_io' matches 'socket.io' after normalizing separators.
 Fix: Use the canonical name 'socket.io' with the correct separators.

5. 단어 재배열

공격: parse-json vs json-parse. Levenshtein 거리는 8입니다 — 편집 거리 검사로는 보이지 않습니다. 그러나 공격자는 재배열된 이름을 등록할 수 있습니다.

sloppy-joe가 차단하는 방법: 구분자로 분할하고, 세그먼트의 모든 순열을 생성한 다음 각각을 코퍼스와 대조합니다. parse-json → 순열 → json-parse → 일치.``` ERROR parse-json [similarity/word-reorder] 'parse-json' is a reordering of 'json-parse'. Fix: Use 'json-parse' — the segments are in the wrong order.

root@kitploit:~
### 6. 인접 문자 교환

**공격:** `reqeust` 대신 `request`. 두 인접 문자가 전치된 일반적인 오타로, 공격자가 악용합니다.

**sloppy-joe가 이를 차단하는 방법:** 의존성 이름의 모든 인접 교환 변형을 생성하여 각각을 코퍼스와 대조합니다.```
ERROR reqeusts [similarity/char-swap]
      'reqeusts' matches 'requests' with two adjacent characters swapped.
 Fix: Use 'requests' — two characters are transposed.

7. 누락된 문자

공격: reqests (u 누락) 대신 requests. AI가 문자 하나를 빠뜨려 유효해 보이는 이름이 생성됩니다.

sloppy-joe가 차단하는 방법: 이름의 모든 위치에 a-z 문자를 하나씩 삽입하고 결과가 알려진 패키지와 일치하는지 확인합니다. reqests + 위치 3에 u → requests → 일치.``` ERROR reqests [similarity/omitted-char] 'reqests' matches 'requests' with one character inserted. Fix: Use 'requests' — a character appears to be missing.

root@kitploit:~
### 8. 호모글리프(시각적 유사 문자)

**공격:** 키릴 문자 `е`(U+0435)가 라틴 문자 `e`(U+0065) 대신 사용된 `rеquests`. 시각적으로 동일합니다. 패키지 이름이 `requests`와 똑같이 보이지만 다른 악성 패키지로 연결됩니다.

**sloppy-joe가 차단하는 방법:** 17개의 알려진 호모글리프 문자(키릴 문자, 전각 문자, 필기체 변형)를 해당 라틴 문자로 대체한 후 결과가 알려진 패키지와 일치하는지 확인합니다.```
ERROR rеquests [similarity/homoglyph]
      'rеquests' contains characters that look identical to 'requests'
      but are different Unicode codepoints (homoglyphs).
 Fix: Replace the lookalike characters with standard ASCII.

9. 생태계 혼동 형태

공격: py-utils vs python-utils. PyPI에서는 이들은 서로 다른 패키지입니다. AI가 하나를 생성할 때 다른 것을 의도한 경우가 발생합니다. 마찬가지로 Go 모듈에서는 github.com vs gitlab.com 문제가 있습니다.

sloppy-joe가 이를 차단하는 방법: 생태계별 대체 규칙을 적용합니다(PyPI의 경우 py↔python, Go의 경우 github↔gitlab). 그런 다음 어떤 변형이 알려진 패키지와 일치하는지 확인합니다.``` ERROR py-flask [similarity/confused-form] 'py-flask' is a confused form of 'flask'. Fix: Use the canonical name 'flask'.

root@kitploit:~
### 10. 대소문자 변형 공격 (대소문자 구분 레지스트리)

**공격:** Go, Maven, Ruby에서는 `Rails`와 `rails`가 서로 다른 패키지입니다. 공격자는 대문자 변형을 등록합니다.

**sloppy-joe가 차단하는 방법:** 대소문자를 구분하는 레지스트리에서는 알려진 패키지의 대소문자 변형이 오류로 플래그 지정됩니다. 대소문자를 구분하지 않는 레지스트리(npm, PyPI, Cargo, NuGet, PHP)에서는 대소문자 변형이 안전하므로 건너뜁니다.```
ERROR Rails [similarity/case-variant]
      'Rails' differs from 'rails' only in letter casing.
      On case-sensitive registries (ruby) these resolve to different packages.
 Fix: Use the exact casing 'rails' in your manifest.

11. 버전 접미사 스쿼팅

공격: requests2 또는 lodash-4. AI가 패키지 이름에 버전 번호를 붙여서 적절한 버전을 지정하지 않습니다.

sloppy-joe가 이를 차단하는 방법: 끝자리 숫자와 구분자를 제거하고 기본 이름이 알려진 패키지와 일치하는지 확인합니다.``` ERROR requests2 [similarity/version-suffix] 'requests2' looks like 'requests' with a version suffix appended. Fix: Use 'requests' and specify the version in your manifest's version field.

root@kitploit:~
### 12. 스코프 스쿼팅 (npm, PHP, Go, JVM)

**공격:** 공격자는 `@typos/lodash`를 npm에 등록합니다 — `@types/lodash`와 한 글자 차이입니다. 또는 Packagist에 `larvael/framework` — `laravel/framework`와 두 글자 차이입니다. 또는 Go에 `github.com/gooogle/protobuf` — `o`가 하나 더 많습니다. 스코프가 언뜻 보기에는 합법적으로 보입니다. 패키지가 확인됩니다. 악성코드가 설치됩니다.

이는 드물지만 가능성이 있는 일이며 — "드물지만 가능성 있는" 것이 바로 sloppy-joe가 존재하는 이유입니다. 2021년 `ua-parser-js` 사건은 스코프 관련이었습니다. 주간 다운로드 수가 수백만인 패키지에서 발생할 수 있다면, 여러분의 패키지에서도 발생할 수 있습니다.

**sloppy-joe가 차단하는 방법:** 의존성 이름에서 스코프/네임스페이스를 추출하고 편집 거리를 사용하여 알려진 양호한 스코프 목록과 비교합니다. npm(`@scope`), PHP(`vendor/`), Go(`github.com/org`), JVM(`com.group`)에서 작동합니다.```
ERROR @typos/lodash [similarity/scope-squatting]
      Scope '@typos' is 1 character away from the known scope '@types'.
      Scope squatting is a known supply chain attack vector.
 Fix: If you meant '@types/lodash', fix the scope in your manifest.

.``` ERROR github.com/gooogle/protobuf [similarity/scope-squatting] Scope 'github.com/gooogle' is 1 character away from 'github.com/google'. Fix: If you meant 'github.com/google/protobuf', fix the org name.

root@kitploit:~
### 13. 비정규 패키지 (공격이 아님 — 일관성 게이트)

**공격:** 공격이 아님 — 일관성 문제입니다. AI가 학습 데이터에서 인기가 많았던 `moment`를 선택했지만, 팀은 `dayjs`를 사용합니다. 동일한 작업에 대해 서로 다른 팀이 다른 패키지를 사용하면 유지보수 부채와 의존성 팽창이 발생합니다.

**sloppy-joe가 차단하는 방법:** 구성 파일에서 각 표준 패키지를 거부된 대안에 매핑합니다. 종속성이 대안과 일치하면 빌드가 실패합니다.```
ERROR moment [canonical]
      'moment' is not the approved package for this purpose.
      Your team uses 'dayjs'.
 Fix: Replace 'moment' with 'dayjs' in your manifest file.

14. 너무 새로운 버전 (공급망 시한폭탄)

공격: 공격자가 패키지 유지보수자의 계정을 탈취하거나(또는 유지보수자가 악의적인 행동을 취하여) 악성 패치 버전을 게시합니다. 이는 정상 업데이트처럼 보입니다. CI가 즉시 설치하면 아무도 알아채기 전에 침해당합니다.

sloppy-joe가 차단하는 방법: 버전 연령 게이트는 min_version_age_hours(기본값: 72시간) 이전에 게시된 버전의 모든 종속성을 차단합니다. 이를 통해 커뮤니티, Socket.dev 및 기타 스캐너가 악성 버전을 플래그할 시간을 확보합니다.``` ERROR react [metadata/version-age] Version '^19.0.0' of 'react' was published 6 hours ago (minimum: 72 hours). New versions need time for the community and security scanners to review them. Fix: Wait until the version is at least 72 hours old, or pin to an older version.

root@kitploit:~
### 15. 새로 생성된 패키지

**공격:** 어제 생성되었고 다운로드 수가 3회인 패키지로, 인기 패키지와 유사한 이름을 가지고 있습니다. 오타 스쿼트나 향후 공격을 위한 자리채움(placeholder)일 가능성이 높습니다.

**sloppy-joe의 차단 방법:** 30일 미만 전에 생성된 모든 패키지를 플래그합니다.```
ERROR sketchy-lib [metadata/new-package]
      'sketchy-lib' was first published 2 days ago.
      New packages are higher risk.
 Fix: Verify 'sketchy-lib' at its registry page and source repository.

16. 다운로드 수가 적은 패키지

공격 방식: 다운로드 수가 12개인 패키지가 requests와 한 글자 차이인 경우. 거의 확실히 타이포스쿼팅입니다.

sloppy-joe가 차단하는 방법: 레지스트리에서 다운로드 데이터를 제공하는 경우(현재 npm, crates.io, RubyGems) 다운로드 수가 100개 미만인 패키지를 플래그합니다.``` ERROR requsets [metadata/low-downloads] 'requsets' has only 12 downloads. Fix: Verify 'requsets' is the package you intend to use.

root@kitploit:~
---

## 지원되는 생태계

| 생태계 | 매니페스트 | Lockfile 정책 | 존재 여부 | 메타데이터 | 연령 게이트 |
|-----------|----------|-----------------|:---------:|:--------:|:--------:|
| npm | package.json | `package-lock.json` 또는 `npm-shrinkwrap.json` 필수 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| PyPI | `pyproject.toml`, `requirements*.txt`, `Pipfile`, `setup.cfg`, `setup.py` | Poetry는 `poetry.lock`으로 신뢰되고, uv는 `uv.lock`으로 신뢰되며, 완전히 해시 잠긴 pip-tools는 커밋된 requirements 그래프가 `--index-url`과 정확히 허용된 `--extra-index-url` 값을 바인딩할 때만 신뢰되며, 리포지토리에서 볼 수 있는 Poetry/uv 사용자 정의 인덱스는 정확한 `trusted_indexes.pypi` 허용 목록에 의해서만 신뢰될 수 있습니다. 레거시 매니페스트는 `python_enforcement`가 `poetry_only`인 경우를 제외하고 매 실행마다 경고합니다. | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Cargo | Cargo.toml | `Cargo.lock` 필수 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Go | go.mod | `go.sum`은 외부 종속성에 필수; stdlib 전용 또는 전체 로컬 `replace`에는 필요하지 않음 | :white_check_mark: | :x: | :x: |
| Ruby | Gemfile | `Gemfile.lock` 필수 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| PHP | composer.json | `composer.lock` 필수 | :white_check_mark: | :x: | :x: |
| JVM (Gradle) | build.gradle / build.gradle.kts | `gradle.lockfile` 필수 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| JVM (Maven) | pom.xml | 경고 전용: 엄격한 lockfile 적용 없음 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| .NET | *.csproj | `packages.lock.json` 필수 | :white_check_mark: | :x: | :x: |

모든 생태계는 존재 여부, 유사성, 표준 검사를 받습니다. 메타데이터와 연령 게이트는 레지스트리 API가 노출하는 항목에 따라 달라집니다. Lockfile 지원을 통해 생태계가 신뢰할 수 있는 프로젝트 로컬 lockfile 모델을 제공하는 경우 전이적 종속성 스캐닝과 정확한 버전 해결이 가능합니다.

## 빠른 시작```bash
# Install
cargo install sloppy-joe

# Check current project (auto-detects ecosystem)
sloppy-joe check

# Check with canonical enforcement and age gate
sloppy-joe check --config /etc/sloppy-joe/config.json

# Output as JSON for CI
sloppy-joe check --json

종료 코드

코드의미
0모든 검사 통과
1문제 발견
2런타임 오류

설정```json

{ "canonical": { "npm": { "lodash": ["underscore", "ramda", "lazy.js"], "dayjs": ["moment", "luxon"], "axios": ["request", "got", "node-fetch", "superagent"] }, "pypi": { "httpx": ["urllib3", "requests"], "ruff": ["flake8", "pylint"] } }, "internal": { "go": ["github.com/yourorg/"], "npm": ["@yourorg/"] }, "allowed": { "npm": ["some-vetted-external-pkg"] }, "similarity_exceptions": { "cargo": [ { "package": "serde_json", "candidate": "serde", "generator": "segment-overlap" } ] }, "metadata_exceptions": { "cargo": [ { "package": "colored", "check": "metadata/maintainer-change", "version": "2.2.0", "previous_publisher": "kurtlawrence", "current_publisher": "hwittenborn" } ] }, "min_version_age_hours": 72, "allow_legacy_npm_v1_lockfile": false, "python_enforcement": "prefer_poetry" }

root@kitploit:~
**`canonical`** — 키는 승인된 패키지, 값은 거부된 대안입니다.

**`internal`** — 조직의 패키지입니다. 모든 검사를 건너뜁니다. 이들은 지속적으로 변경됩니다.

**`allowed`** — 검증된 외부 패키지입니다. 존재 여부 및 유사성 검사를 건너뛰지만, 여전히 버전 기간 게이트의 적용을 받습니다.

**`similarity_exceptions`** — 검토된 유사성 오탐지에 대한 정확한 패키지/후보/생성기 억제입니다. 특정 유사성 에지가 잘못되었지만 패키지에 대한 정상 검사를 원할 때 사용합니다.

**`metadata_exceptions`** — 검토된 메타데이터 억제입니다. 현재는 `metadata/maintainer-change`만 지원하며, 정확한 패키지/버전/이전 게시자/현재 게시자 일치가 필요합니다.

유지자 변경 차단을 검토해야 할 때 `sloppy-joe check --review-exceptions`를 사용하세요. 스캔은 여전히 정상적으로 차단되지만, 사람이 읽을 수 있는 출력에는 소유자, 저장소 URL, 복사하여 붙여넣을 수 있는 `metadata_exceptions` 스니펫이 포함된 `REVIEW EXCEPTIONS` 섹션이 추가됩니다. `--json`은 동일한 데이터를 최상위 `review_candidates` 필드에 포함합니다.

**`min_version_age_hours`** — 이 시간보다 전에 게시된 버전을 차단합니다. 기본값: 72(3일). 비활성화하려면 0으로 설정하세요. 내부 패키지는 면제됩니다.

**`allow_legacy_npm_v1_lockfile`** — 축소된 신뢰 모드에서 npm v5/v6의 `lockfileVersion: 1` npm 잠금 파일을 허용합니다. 기본값: `false`. 레거시 npm에 의도적으로 고정되어 있고 큰 경고와 축소된 신뢰할 수 있는 npm 전이 적용 범위를 수용하지 않는 한 이 옵션을 끄십시오.

**`python_enforcement`** — Python 신뢰 정책을 제어합니다. `prefer_poetry`(기본값)는 Poetry 프로젝트와 uv 프로젝트를 신뢰하며, 커밋된 요구사항 그래프가 `--index-url` 및 모든 비PyPI `--extra-index-url` 값을 정확히 바인딩하는 경우에만 완전 해시 잠금된 pip-tools 요구사항을 신뢰하고, 그렇지 않으면 pip-tools를 축소된 신뢰로 강등합니다. 해시되지 않은 `requirements*.txt`, `Pipfile`, `setup.cfg`, `setup.py`, Poetry/uv가 아닌 `pyproject.toml`과 같은 레거시 매니페스트는 실행할 때마다 경고합니다. `poetry_only`는 이러한 비Poetry Python 워크플로를 차단하고 Poetry를 요구합니다.

### 구성 보안

구성은 **프로젝트 디렉토리에서 절대 읽지 않습니다**. 셸 접근 권한이 있는 AI 에이전트가 저장소 내 구성을 다시 작성하여 원하는 모든 것을 허용 목록에 추가할 수 있습니다.

구성 해결:
1. `--config /path/to/config.json` — 로컬 파일(CLI 플래그, 최고 우선순위)
2. `--config https://example.com/config.json` — URL에서 가져오기
3. `SLOPPY_JOE_CONFIG=...` — 환경 변수(파일 경로 또는 URL)
4. 구성 없음 = 존재 여부 + 유사성 + 메타데이터 검사만 수행

잘못된 구성은 실행 가능한 오류 메시지와 함께 **하드 실패**합니다 — 손상된 구성이 조용히 보호 없음으로 대체되지 않습니다.

전체 형식 참조, CI 통합 패턴 및 예제는 [CONFIG.md](https://github.com/brennhill/sloppy-joe/blob/main/CONFIG.md)를 참조하세요.

부트스트랩 구성:```bash
sloppy-joe init --greenfield --ecosystem npm
sloppy-joe init --from-current
sloppy-joe init --from-current --register
sloppy-joe init --register

CI 통합

GitHub Actions

CI 파이프라인에 sloppy-joe를 추가하는 가장 빠른 방법 — GitHub Releases에서 사전 빌드된 바이너리를 다운로드합니다 (Rust 툴체인 불필요):```yaml

.github/workflows/deps.yml

name: Dependency Check on: [push, pull_request]

jobs: sloppy-joe: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: brennhill/[email protected] with: config: https://raw.githubusercontent.com/yourorg/configs/main/sloppy-joe.json

root@kitploit:~
#### 작업 입력

| 입력 | 설명 | 기본값 |
|-------|-------------|---------|
| `config` | 설정 파일 경로 또는 HTTPS URL | *(없음)* |
| `dir` | 스캔할 프로젝트 디렉터리 | `.` |
| `type` | 생태계 (`npm`, `pypi`, `cargo`, `go`, `ruby`, `php`, `jvm`, `dotnet`) | 자동 감지 |
| `deep` | 전이 종속성 유사성 검사 활성화 | `false` |
| `paranoid` | 비트플립 변형 활성화 | `false` |
| `args` | 추가 CLI 인수 | *(없음)* |
| `version` | 설치할 sloppy-joe 버전 | `latest` |

#### 예제```yaml
# Minimal — CI-oriented scan, auto-detect ecosystem, no config
- uses: brennhill/[email protected]

# With org config from a URL
- uses: brennhill/[email protected]
  with:
    config: https://raw.githubusercontent.com/yourorg/configs/main/sloppy-joe.json

# Deep scan with paranoid mode
- uses: brennhill/[email protected]
  with:
    config: ${{ secrets.SLOPPY_JOE_CONFIG }}
    deep: true
    paranoid: true

# Scan a subdirectory, pin to a specific version
- uses: brennhill/[email protected]
  with:
    dir: ./packages/api
    version: '1.1.0'

GitLab CI```yaml

dependency-guard: script: - cargo install sloppy-joe - sloppy-joe check --ci --config $SLOPPY_JOE_CONFIG

root@kitploit:~
### pre-commit

sloppy-joe는 [pre-commit](https://pre-commit.com) 프레임워크와 함께 작동합니다.
`.pre-commit-config.yaml`에 추가하세요:```yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/brennhill/sloppy-joe
    rev: v1.1.0
    hooks:
      - id: sloppy-joe

이 훅은 모든 커밋(및 선택적으로 푸시)에서 sloppy-joe check를 실행합니다. 매니페스트 파일에서 생태계를 자동으로 감지합니다. 추가 인수를 전달 args를 통해:```yaml - id: sloppy-joe args: [--config, "https://example.com/config.json"]

root@kitploit:~
또는 프레임워크 없이 간단한 셸 훅을 사용하세요:```bash
#!/bin/sh
sloppy-joe check || exit 1

아키텍처

sloppy-joe는 유사성 탐지를 위해 레지스트리 기반 생성 접근 방식을 사용합니다. 모든 종속성을 정적 코퍼스와 편집 거리로 비교하는 대신(이는 오탐을 발생시킵니다), 각 종속성 이름의 특정 변형을 생성하고, 해당 변형이 존재하는지 레지스트리에 질의한 후 정확히 일치하는 항목을 플래그합니다.``` Pipeline (in order):

  1. Canonical check — flag deps that violate org standards
  2. Similarity check — 8 mutation generators + scope squatting
  3. Metadata check — version age, new package, downloads, install scripts, dep explosion, maintainer change
  4. Existence check — flag packages that don't exist on the registry
  5. Malicious check — query OSV.dev for known vulnerabilities
root@kitploit:~
유사성 검사는 4단계로 실행됩니다.
- **0단계: 범위 스쿼팅** — 로컬 검사, 네트워크 없음. Levenshtein 거리를 통해 알려진 정상 범위/네임스페이스와 비교합니다.
- **1단계: 매니페스트 내부** — 로컬 검사. 동일한 매니페스트의 두 의존성이 서로 변형(mutation)인 경우 플래그를 지정합니다.
- **2단계: 레지스트리 쿼리** — 변형을 생성하고, 레지스트리에 일괄 쿼리하여 존재 여부를 확인한 후 결과를 캐싱합니다(7일 TTL).
- **3단계: 메타데이터 보강** — 일치 항목에 대한 다운로드 수와 게시 날짜를 가져와 보고서에 증거를 추가합니다.

각 변형 생성기는 출력에 태그를 지정하므로, 보고된 검사 유형(예: `similarity/homoglyph`)은 결정적입니다. 여러 생성기가 동일한 후보를 생성하는 경우 가장 심각도가 높은 생성기가 우선합니다.

## CI 신뢰성

sloppy-joe는 불안정한 실패가 허용되지 않는 CI 파이프라인을 위해 설계되었습니다.

**백오프(backoff)를 통한 재시도.** 모든 레지스트리 HTTP 호출은 일시적 오류(5xx, 타임아웃, 연결 오류) 발생 시 지수 백오프(200ms, 400ms, 800ms)로 3회 재시도합니다. 단 한 번의 네트워크 오류로 빌드가 실패하지 않습니다.

**쿼리 오류 시 장애-폐쇄(fail-closed).** 레지스트리 또는 OSV 쿼리가 실패하면, sloppy-joe는 검사를 조용히 건너뛰는 대신 차단 오류 `registry-unreachable`을 발생시킵니다. 더 이상 검사가 차단되기 전에 생태계별 임계값이나 샘플 크기 제한에 의존하지 않습니다.

**유사성 캐시.** 변형 존재 결과는 7일 동안 캐시됩니다. 첫 번째 검사 이후 대부분의 쿼리는 네트워크 호출 없이 캐시에서 처리됩니다. 새 의존성만 레지스트리 쿼리를 트리거합니다.

**잠금 파일 인식 해결.** 지원되는 잠금 파일이 있고 신뢰할 수 있는 경우(`package-lock.json`, `npm-shrinkwrap.json`, `Cargo.lock`, `Gemfile.lock`, Poetry 프로젝트의 `poetry.lock`, uv 프로젝트의 `uv.lock`, `composer.lock`, `gradle.lockfile`, `packages.lock.json`), sloppy-joe는 범위에서 추측하는 대신 잠금 파일에서 정확한 버전을 확인합니다. 완전 해시 잠금된 `requirements*.txt`도 정확한 고정 버전을 제공할 수 있으며, 커밋된 요구 사항 그래프가 자체 `--index-url`과 정확히 허용된 `--extra-index-url` 값을 바인딩할 때 완전히 신뢰됩니다.

## 테스트

테스트 스위트는 유사성 검사, 메타데이터 신호, OSV 동작, 구성 파싱 및 검증, 잠금 파일 해결, 매니페스트 및 잠금 파일 사전 점검 정책, 보고서 형식화, HTTP 재시도 로직을 다룹니다.```bash
cargo test

기반 기술

  • Typomania — Rust Foundation의 오타 스쿼팅 라이브러리로, 생성적 변형 접근 방식에 영감을 제공 (sloppy-joe는 크레이트를 직접 사용하지 않고 자체 생성기 구현)
  • strsim — Levenshtein 거리, 스코프 스쿼팅 탐지에 사용
  • reqwest — 레지스트리 조회를 위한 재시도 기능이 있는 비동기 HTTP 클라이언트
  • OSV.dev — 악성 패키지 탐지를 위한 알려진 취약점 데이터베이스

sloppy-joe 비교

기능sloppy-joeSocket.devcargo-denypip-auditnpm audit
환각(hallucinated) 패키지 탐지✅❌❌❌❌
오타 스쿼팅 탐지✅ 11개 생성기부분적❌❌❌
표준 이름 강제 적용✅❌❌❌❌
알려진 취약점 스캔✅ OSV 통해✅✅✅✅
설치 스크립트 분석기본 (플래그 + 저장소 없음)✅ 심층 분석❌❌❌
라이선스 준수범위 외: 준수, 보안 아님✅✅ 훌륭함범위 외: 준수, 보안 아님범위 외: 준수, 보안 아님
다중 생태계8개 생태계npm, PyPI, Go, Ruby, Java, .NETRust 전용Python 전용npm 전용
AI 에이전트 안전성 (저장소 외부 설정)✅❌❌❌❌
오프라인/CI 친화적✅ 어디서든 실행Socket 플랫폼 필요✅✅✅
무료 / 오픈 소스Apache 2.0무료 티어 + 유료Apache 2.0Apache 2.0내장

타 도구가 더 강한 부분: Socket.dev는 sloppy-joe의 플래그 기반 접근 방식을 훨씬 뛰어넘는 행동 탐지를 통한 심층 설치 스크립트 분석을 수행합니다. cargo-deny는 최고 수준의 라이선스 준수 확인 기능을 제공하지만, 이는 의도적으로 sloppy-joe의 범위 밖입니다. 라이선스 정책은 종속성 보안 제어가 아니라 준수 문제이기 때문입니다. npm audit과 pip-audit은 단일 생태계 취약점 스캔을 위한 설치 없는(zero-install) 옵션입니다.

sloppy-joe의 차별점: 패키지가 실제로 레지스트리에 존재하는지 확인(AI 환각 탐지), 거의 오탐 없이 11개의 오타 스쿼팅 생성기 실행, 표준 패키지 선택 강제, 그리고 AI 에이전트가 자체 검사를 약화시킬 수 없도록 설정을 저장소 외부에 유지하는 유일한 도구입니다.

라이선스

Apache 2.0

도구 다운로드
❌
❌
npm✅✅✅✅❌
PyPI✅✅✅✅✅
Cargo✅✅❌✅❌
Go✅✅✅❌❌
Ruby✅✅✅❌❌
PHP✅🔶❌❌❌
JVM (Gradle/Maven)✅✅❌❌❌
.NET (NuGet)✅✅❌❌❌
단일 바이너리✅❌❌❌❌
오픈소스Apache 2.0상용Apache 2.0MITOSS
언어RustSaaSPythonPythonPython