Skip to main content
hook official · GitHub

attester-import-check — GitHub Copilot hook: setup and usage

The hook inspects code edits in GitHub Copilot and checks PyPI and npm package names via attester.dev. It blocks tool calls that introduce nonexistent dependencies.

Install into Claude Code · Manually: put the files in place All methods and platforms ↓
.claude/settings.json
Open on GitHub

What attester-import-check does

The script executes on the preToolUse event before the agent writes code to disk. It reads import statements from the incoming payload and verifies them against the attester.dev database. The oracle checks real wheels and tarballs on PyPI and npm, making the answer deterministic. Nonexistent packages trigger an exit code 1. The edit stops immediately.

Without Python 3.10+ in your environment, this check will not run. It relies entirely on the standard library, so no extra packages are installed. The free tier allows 25 checks per day per IP address, resetting at 00:00 UTC. Results stay in ~/.cache/attester-import-check/cache.json for 30 days. Because answers are cached, repeated file edits do not drain your daily quota. Network timeouts or exhausted limits fail open with code 0.

Private packages will register as missing because the oracle only checks public registries. Names where the import differs from the distribution, such as yaml or PIL, require manual entries in .attester-allowlist. Dynamic imports via __import__ and bundler aliases are also ignored.

What it helps with

  • block hallucinated PyPI and npm dependencies before files are written
  • verify third-party package existence against published registry artifacts
  • whitelist packages with differing import names in .attester-allowlist
  • cache verification results locally to preserve the daily quota

Example prompts for the agent

  • Add an HTML parsing function to main.py using BeautifulSoup.
  • Create a Node.js utility for date formatting and import the required package.
  • Write a Python script to validate input data using an external package.

How to install attester-import-check

Manually: put the files in place

.claude/settings.json

The hooks block: event (PreToolUse, PostToolUse, Stop…) → command. Personal ones go to ~/.claude/settings.json

Step by step, with commands for each platform: Claude Code hooks: what they are, where to configure them, how to block a risky command

Questions about attester-import-check

How to install attester-import-check in GitHub Copilot?

Copy the hook directory to your project with cp -r hooks/attester-import-check your-repo/hooks/ and make it executable via chmod +x hooks/attester-import-check/check-imports.py. Next, register the script under preToolUse in hooks.json (or .claude/settings.json).

What does attester-import-check do?

The hook intercepts tool calls before code is written, parses third-party package imports, and checks them against real PyPI and npm artifacts via attester.dev. If an import does not exist in the registry, the hook exits with status 1 to block the change.

What happens when the daily quota is exhausted?

The free tier provides 25 checks per day per client IP. Once the quota is spent or if the API cannot be reached, the hook logs a warning and exits with code 0 to allow the edit without blocking.

Source text

attester-import-check · MIT
---
name: 'Attester Import Check'
description: 'Verifies PyPI and npm package names against the attester.dev existence oracle before the Copilot coding agent writes them into code, blocking hallucinated dependencies'
tags: ['security', 'supply-chain', 'preToolUse', 'dependencies']
---

# Attester Import Check Hook

Verifies every third-party package name the Copilot coding agent is about to write into code, before the write lands. A USENIX Security 2025 study measured 5.2% to 21.7% of LLM-suggested package names as nonexistent; this hook catches those names at the door.

## Overview

On the `preToolUse` event the hook receives the tool invocation as JSON on stdin, extracts import statements from the code being introduced, and checks each package name against the attester.dev existence oracle. The oracle answers from real published artifacts (PyPI wheels, npm tarballs), so a "does not exist" answer is deterministic, not a model opinion.

## Behavior contract

- **Blocks (exit 1)** only on a confident negative from the oracle.
- **Fails open (exit 0)** when the free daily quota is spent, the API is unreachable, or the payload is unusable. It never blocks on these.
- Python: skips standard library modules and relative imports. JS/TS: skips relative paths, absolute paths, and node builtins; `@scope/name` handled.
- Answers are cached at `~/.cache/attester-import-check/cache.json` (exists 30 days, negatives 1 day) so repeated edits do not burn the free quota.
- Allowlist import names that differ from their registry package (`yaml`, `PIL`, `cv2`) via `.attester-allowlist` in the workspace root, one per line.

## Free quota and the paid path

The check uses the free keyless tier: 25 calls per day per client IP, no account or API key, reset 00:00 UTC. Over quota the hook prints "attester quota exhausted, unchecked" and allows the operation. High volume: $0.002 per package check on the paid route (x402 or prepaid credits), documented at https://attester.dev/llms.txt.

## Installation

1. Copy the hook folder to your repository:

   ```bash
   cp -r hooks/attester-import-check your-repo/hooks/
   ```

2. Ensure the script is executable:

   ```bash
   chmod +x hooks/attester-import-check/check-imports.py
   ```

3. Commit the hook configuration to your repository's default branch.

The script is Python 3.10+ standard library only. No pip install step.

## Configuration

The hook is configured in `hooks.json` to run on the `preToolUse` event:

```json
{
  "version": 1,
  "hooks": {
    "preToolUse": [
      {
        "type": "command",
        "bash": "hooks/attester-import-check/check-imports.py",
        "cwd": ".",
        "env": {
          "ATTESTER_MODE": "block"
        },
        "timeoutSec": 30
      }
    ]
  }
}
```

### Environment Variables

| Variable | Values | Default | Description |
|----------|--------|---------|-------------|
| `ATTESTER_MODE` | `block`, `warn` | `block` | `warn` prints findings but always allows the operation |
| `ATTESTER_BASE_URL` | URL | `https://attester.dev` | Oracle base URL |
| `ATTESTER_IMPORT_CHECK_NO_CACHE` | `1` | unset | Skip the on-disk answer cache |

## Examples

### Hallucinated package (exit 1, blocked)

```bash
echo '{"toolName":"write_file","toolInput":{"path":"main.py","content":"import requestsx_fantasy_helper"}}' | \
  python3 hooks/attester-import-check/check-imports.py
```

```
attester-import-check: 'requestsx_fantasy_helper' does not exist on PyPI (attester.dev oracle). Remove or fix the import, or add the name to .attester-allowlist if this is a false positive.
```

### Real package (exit 0)

```bash
echo '{"toolName":"write_file","toolInput":{"path":"main.py","content":"import requests"}}' | \
  python3 hooks/attester-import-check/check-imports.py
```

### Quota exhausted (exit 0, allowed with warning)

```
attester-import-check: attester quota exhausted, unchecked
```

## Limitations

- Import names that differ from distribution names (`yaml` for PyYAML, `PIL` for Pillow) can warn falsely; allowlist them.
- Python dynamic imports (`__import__`, `importlib.import_module`) and bundler path aliases are not resolved.
- The hook checks names against a public registry oracle; private packages are "not found" there by design.

## Source project

The standalone version of this guard (pre-commit hook, Claude Code hook, GitHub Action) lives at https://github.com/maminihds/attester-import-check. The oracle behind it is https://attester.dev.


```json
{
  "version": 1,
  "hooks": {
    "preToolUse": [
      {
        "type": "command",
        "bash": "hooks/attester-import-check/check-imports.py",
        "cwd": ".",
        "env": {
          "ATTESTER_MODE": "block"
        },
        "timeoutSec": 30
      }
    ]
  }
}

```

© github · MIT · github/awesome-copilot

Similar hooks

All hooks for Security →

From the same set954

The whole set →
secrets-scanner Scans the files a Copilot coding agent touched during a session for leaked keys and credentials before they get committed. Useful when the agent edits code fast. ★ 40,451repo stars governance-audit Scans GitHub Copilot prompts for threat patterns before execution. It records events to a local JSON log and stops destructive actions based on governance settings. ★ 40,451repo stars fix-broken-links This hook checks links in recently edited web files after GitHub Copilot uses a tool. It helps catch dead URLs and vague link labels before they linger in the project. ★ 40,451repo stars dependency-license-checker A GitHub Copilot hook that scans newly added dependencies at session end and flags copyleft licenses before they get committed. ★ 40,451repo stars Workshop TA Coordinates a group of persistent AI workstreams by routing tasks, reading journals, and surfacing blocks or completed work. Use it to keep a multi-agent workshop organized. ★ 40,451repo stars WG Code Sentinel A GitHub Copilot subagent that reviews code and configs for vulnerabilities and hands you concrete fixes. Useful before a merge or a release. ★ 40,451repo stars WG Code Alchemist Subagent refactors messy code using Clean Code practices and SOLID principles. It helps eliminate code smells, decouple tightly coupled classes, and clarify obscure logic. ★ 40,451repo stars Expert Vue.js Frontend Engineer GitHub Copilot subagent specialized in Vue 3, Composition API, TypeScript, and component architecture. Builds frontends, migrates from Vue 2, and optimizes rendering. ★ 40,451repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor