{"id":50958892,"url":"https://github.com/wjddusrb03/pkghall","last_synced_at":"2026-06-18T11:02:48.672Z","repository":{"id":356538429,"uuid":"1232968124","full_name":"wjddusrb03/pkghall","owner":"wjddusrb03","description":"Detect hallucinated (non-existent) packages in AI-generated code","archived":false,"fork":false,"pushed_at":"2026-05-08T13:23:43.000Z","size":53,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-08T15:35:28.610Z","etag":null,"topics":["ai-safety","cli","hallucination","llm","pypi","python","security","slopsquatting"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wjddusrb03.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T13:02:21.000Z","updated_at":"2026-05-08T13:23:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/wjddusrb03/pkghall","commit_stats":null,"previous_names":["wjddusrb03/pkghall"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/wjddusrb03/pkghall","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wjddusrb03%2Fpkghall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wjddusrb03%2Fpkghall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wjddusrb03%2Fpkghall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wjddusrb03%2Fpkghall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wjddusrb03","download_url":"https://codeload.github.com/wjddusrb03/pkghall/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wjddusrb03%2Fpkghall/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34487081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-safety","cli","hallucination","llm","pypi","python","security","slopsquatting"],"created_at":"2026-06-18T11:02:47.981Z","updated_at":"2026-06-18T11:02:48.645Z","avatar_url":"https://github.com/wjddusrb03.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pkghall\n\n**AI가 생성한 코드에서 존재하지 않는 패키지를 찾아냅니다.**\n\n[![CI](https://github.com/wjddusrb03/pkghall/actions/workflows/ci.yml/badge.svg)](https://github.com/wjddusrb03/pkghall/actions/workflows/ci.yml)\n[![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)\n\n---\n\n## 문제: AI는 존재하지 않는 패키지를 당당하게 추천한다\n\nChatGPT, Claude, Copilot 같은 LLM은 코드를 생성할 때 **실제로 PyPI에 없는 패키지 이름을 만들어내는** 경우가 있습니다. 이를 **패키지 환각(package hallucination)** 이라고 부릅니다.\n\n연구에 따르면 LLM이 추천하는 패키지의 **약 20%가 PyPI에 존재하지 않습니다** ([출처](https://www.aikido.dev/blog/slopsquatting-ai-package-hallucination-attacks)).\n\n이것이 단순한 오류로 끝나지 않는 이유가 있습니다 — **슬롭스쿼팅(slopsquatting)** 공격입니다.\n\n```\nLLM이 \"langchain-utils-extra\" 라고 추천\n    ↓\n실제로는 PyPI에 없는 이름\n    ↓\n공격자가 미리 해당 이름으로 악성 패키지를 등록해둠\n    ↓\n개발자가 pip install langchain-utils-extra 실행\n    ↓\n악성 코드 실행, 자격 증명 탈취\n```\n\n`pkghall`은 `pip install`을 실행하기 **전에** 패키지 이름을 검증해서 이 공격을 차단합니다.\n\n---\n\n## 동작 방식\n\n1. Python 소스 파일(`.py`) 또는 `requirements.txt`에서 패키지 이름을 추출합니다.\n2. 표준 라이브러리 모듈(`os`, `sys`, `json` 등)과 잘 알려진 import 별칭(`cv2` → `opencv-python`, `PIL` → `Pillow` 등)을 자동으로 제외합니다.\n3. 각 패키지를 **PyPI JSON API**에 비동기로 병렬 조회합니다 (기본 동시 요청 10개).\n4. 존재하지 않는 패키지, 신규 등록 패키지, 다운로드 수가 낮은 패키지를 분류하여 보고합니다.\n\n---\n\n## 설치\n\nPython 3.11 이상이 필요합니다.\n\n```bash\ngit clone https://github.com/wjddusrb03/pkghall.git\ncd pkghall\npip install -e .\n```\n\n파일 감시(watch) 모드까지 사용하려면:\n\n```bash\npip install -e \".[watch]\"\n```\n\n개발 환경 (테스트 포함):\n\n```bash\npip install -e \".[dev]\"\n```\n\n---\n\n## 명령어\n\n### `pkghall check` — requirements 파일 검사\n\n`requirements.txt` 형식의 파일을 받아 각 패키지가 PyPI에 실제로 존재하는지 확인합니다.\n\n```bash\npkghall check requirements.txt\n```\n\n**출력 예시:**\n\n```\nParsed as requirements — found 6 package name(s)\nChecking 6 package(s) on PyPI…\n\n Status        Package                          Age    Note\n ─────────────────────────────────────────────────────────────────────────────────\n ✓             httpx                            2041d  A next generation HTTP client\n ✓             fastapi                          2193d  FastAPI framework, high performance\n ✓             pydantic                         2987d  Data validation using Python type hints\n ✓             requests                         5240d  Python HTTP for Humans.\n ✗ NOT FOUND   fastapi-auth-utils                  —   hallucination or typo\n ✗ NOT FOUND   langchain-tools-extra               —   hallucination or typo\n\n 4 ok  2 NOT FOUND\n\nHallucinated packages:\n  ✗ fastapi-auth-utils\n  ✗ langchain-tools-extra\n```\n\n**지원하는 파일 형식:**\n\n- `requirements.txt`, `requirements-dev.txt`, `requirements-test.txt`\n- `requirements-*.txt` 형태의 모든 파일\n- `extras` 지정 무시: `fastapi[all]==0.100.0` → `fastapi` 로만 검사\n- 환경 마커 무시: `numpy; python_version \u003e= \"3.9\"` → `numpy` 로만 검사\n- `git+https://...`, `--index-url`, `#` 주석 줄 자동 제외\n\n```bash\n# 표준 입력(stdin)으로도 사용 가능\ncat requirements.txt | pkghall check -\n```\n\n---\n\n### `pkghall scan` — Python 소스 파일 검사\n\n`.py` 파일에서 `import` 문을 파싱하여 실제로 존재하는 패키지인지 확인합니다.\n\n```bash\npkghall scan ai_generated_code.py\n```\n\n**출력 예시:**\n\n```\nScanned ai_generated_code.py as python — found 8 import(s)\nChecking 8 package(s) on PyPI…\n\n Status        Package                          Age    Note\n ─────────────────────────────────────────────────────────────────────────────────\n ✓             httpx                            2041d  A next generation HTTP client\n ✓             numpy                            5890d  Fundamental package for array computing\n ✓             pandas                           5621d  Powerful data structures for data analysis\n ✗ NOT FOUND   openai-utils-pro                    —   hallucination or typo\n ⚠ suspicious  ai-helper-framework               12d   new or unpopular — verify before installing\n\n 3 ok  1 NOT FOUND  1 suspicious\n```\n\n**파싱 방식:**\n\n- `import requests` → `requests`\n- `from PIL import Image` → `Pillow` (import 별칭 자동 변환)\n- `from sklearn.ensemble import ...` → `scikit-learn` (자동 변환)\n- `import os, sys, json` → 표준 라이브러리이므로 제외\n- 상대 import (`from .utils import ...`) 제외\n- `TYPE_CHECKING` 블록, `try/except ImportError` 블록 내 import도 포함\n- 문법 오류가 있는 파일은 정규식 폴백으로 처리\n\n```bash\n# stdin 지원\ncat ai_code.py | pkghall scan -\n```\n\n---\n\n### `pkghall watch` — 파일 감시 모드\n\n디렉토리를 감시하다가 `.py` 파일이나 `requirements*.txt`가 저장될 때마다 자동으로 검사합니다. AI 코드를 에디터에서 붙여넣는 즉시 결과를 볼 수 있습니다.\n\n```bash\n# 현재 디렉토리 감시\npkghall watch\n\n# 특정 디렉토리 감시\npkghall watch ./my-project\n```\n\n**출력 예시 (파일 저장 시):**\n\n```\npkghall watch monitoring /home/user/my-project\nWatching .py and requirements files. Press Ctrl+C to stop.\n\n──────────── requirements.txt ────────────\n  ✓ All 5 package(s) OK\n\n──────────── ai_code.py ────────────\n  ✗ NOT FOUND  openai-plugin-extra\n  ⚠ suspicious  llm-agent-tools  (age 8d)\n```\n\n\u003e `watchdog` 패키지가 필요합니다: `pip install -e \".[watch]\"`\n\n---\n\n### `pkghall setup-hook` — git hook 자동 설치\n\n커밋 전에 자동으로 pkghall이 실행되도록 설정합니다.\n\n**pre-commit 프레임워크 사용 (권장):**\n\n```bash\npkghall setup-hook --type pre-commit\n```\n\n`.pre-commit-config.yaml`에 자동으로 아래 내용을 추가합니다:\n\n```yaml\nrepos:\n  - repo: https://github.com/wjddusrb03/pkghall\n    rev: v0.1.0\n    hooks:\n      - id: pkghall-check   # requirements*.txt 파일 검사\n      - id: pkghall-scan    # Python 소스 파일 검사\n```\n\n이후 한 번만 실행:\n\n```bash\npre-commit install\n```\n\n**raw git hook 사용 (pre-commit 없이):**\n\n```bash\npkghall setup-hook --type git-hook\n```\n\n`.git/hooks/pre-commit` 스크립트를 직접 작성합니다. `pre-commit` 프레임워크 없이도 동작합니다.\n\n---\n\n## 공통 옵션\n\n| 옵션 | 설명 |\n|------|------|\n| `--json` | JSON 형식으로 출력 (CI 파이프라인 연동용) |\n| `--quiet` / `-q` | 진행 메시지 숨김 (스크립트 사용 시) |\n\n---\n\n## JSON 출력\n\n`--json` 플래그를 붙이면 구조화된 JSON을 반환합니다. CI에서 결과를 파싱하거나 다른 도구와 연동할 때 사용합니다.\n\n```bash\npkghall check requirements.txt --json\n```\n\n```json\n[\n  {\n    \"name\": \"httpx\",\n    \"exists\": true,\n    \"age_days\": 2041,\n    \"latest_version\": \"0.27.0\",\n    \"is_suspicious\": false,\n    \"summary\": \"A next generation HTTP client\"\n  },\n  {\n    \"name\": \"fastapi-auth-utils\",\n    \"exists\": false,\n    \"age_days\": null,\n    \"latest_version\": null,\n    \"is_suspicious\": false,\n    \"summary\": null\n  }\n]\n```\n\n**필드 설명:**\n\n| 필드 | 타입 | 설명 |\n|------|------|------|\n| `name` | string | 패키지 이름 |\n| `exists` | bool \\| null | `true`=존재, `false`=없음, `null`=네트워크 오류 |\n| `age_days` | int \\| null | 최초 릴리스 후 경과 일수 |\n| `latest_version` | string \\| null | 최신 버전 |\n| `is_suspicious` | bool | 의심 패키지 여부 |\n| `summary` | string \\| null | PyPI 패키지 요약 |\n\n---\n\n## 의심 패키지 탐지 기준\n\n단순히 \"존재 여부\"를 넘어서, 다음 조건을 만족하면 **⚠ suspicious** 로 표시합니다.\n\n| 조건 | 기준 | 이유 |\n|------|------|------|\n| 신규 등록 | 최초 릴리스 후 30일 미만 | 슬롭스쿼팅 공격은 LLM이 자주 생성하는 이름을 미리 등록해두는 방식 |\n| 낮은 트래픽 | 월 다운로드 100 미만 + 출시 180일 미만 | 실제로 쓰이지 않는 패키지가 이름만 선점한 경우 |\n\n의심 패키지는 자동으로 차단하지 않습니다. 직접 PyPI 페이지를 확인하고 판단하세요.\n\n---\n\n## import 별칭 자동 변환\n\nPython에서 import 이름과 PyPI 패키지 이름이 다른 경우가 많습니다. pkghall은 180개 이상의 별칭을 자동으로 변환합니다.\n\n| import 이름 | PyPI 패키지 이름 |\n|------------|----------------|\n| `PIL` | `Pillow` |\n| `cv2` | `opencv-python` |\n| `sklearn` | `scikit-learn` |\n| `bs4` | `beautifulsoup4` |\n| `yaml` | `PyYAML` |\n| `dotenv` | `python-dotenv` |\n| `serial` | `pyserial` |\n| `Crypto` | `pycryptodome` |\n| `google.cloud` | `google-cloud` |\n| ... | (총 180개+) |\n\n---\n\n## CI/CD 연동 (GitHub Actions)\n\n```yaml\n# .github/workflows/security.yml\nname: pkghall security check\n\non: [push, pull_request]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with:\n          python-version: \"3.12\"\n      - name: Install pkghall\n        run: |\n          git clone https://github.com/wjddusrb03/pkghall.git\n          pip install -e ./pkghall\n      - name: Check requirements\n        run: pkghall check requirements.txt\n      - name: Scan source files\n        run: pkghall scan src/\n```\n\n`pkghall`은 문제가 있을 때 **exit code 1**을 반환하므로 CI가 자동으로 실패 처리합니다.\n\n---\n\n## 종료 코드\n\n| 코드 | 의미 |\n|------|------|\n| `0` | 모든 패키지가 존재하고 의심스럽지 않음 |\n| `1` | 하나 이상의 패키지가 존재하지 않거나 의심스러움 |\n\n---\n\n## 요구 사항\n\n- Python 3.11 이상\n- 인터넷 연결 (PyPI API 조회)\n- watchdog 4.0+ (watch 모드 사용 시만)\n\n---\n\n## 한계\n\n- **비공개 패키지**: 사내 패키지 인덱스나 PyPI에 없는 사설 패키지는 \"NOT FOUND\"로 표시될 수 있습니다.\n- **네트워크 오류**: PyPI 조회에 실패하면 `⚠ timeout`으로 표시되며 종료 코드 0을 반환합니다 (오탐 방지).\n- **Conda 패키지**: PyPI를 기준으로만 검사합니다. Conda 전용 패키지는 지원하지 않습니다.\n- **동적 import**: `importlib.import_module(\"pkg\")` 형태의 동적 import는 감지하지 못합니다.\n\n---\n\n## 라이선스\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwjddusrb03%2Fpkghall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwjddusrb03%2Fpkghall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwjddusrb03%2Fpkghall/lists"}