Find the secrets your AI code editor is about to send to the model.
An AI code editor indexes your repository and streams file contents to a remote
model to power completions and chat. That's the feature. The problem: it will
happily index your .env, your id_rsa, your terraform.tfstate — unless you
explicitly exclude them. These editors give you an ignore file (.cursorignore,
.aiexclude) to do that, but nothing tells you when a secret isn't covered.
Nothing fails. The completions keep working. The key just quietly leaves your
machine.
veilcheck is that missing warning: a zero-config, fully offline auditor that
scans a repo for sensitive files that are not excluded from AI-editor
indexing, and fails the build so the leak never ships.
$ veilcheck .
● 2 exposed sensitive file(s):
.env environment file (.env*) — not excluded from AI-editor context
↳ add to .cursorignore: .env
[VC001]
deploy/prod.pem PEM key/cert file — not excluded from AI-editor context
↳ add to .cursorignore: /deploy/prod.pem
[VC001]
2 blockers · 0 warnings
Exit code 1 when a sensitive file is exposed, so it drops straight into
pre-commit or CI.
veilcheck walks the repo and, for every file, asks two questions:
- Is it sensitive? — by name/type (
.env*except.env.example,*.pem,*.key,id_rsa*,*.p12,credentials,*.kdbx, service-account JSON,*.tfstate), or by content (a file that embeds an AWSAKIA…key or a-----BEGIN … PRIVATE KEY-----block, even under an innocent name). - Is it excluded? — is the file covered by a glob in
.cursorignore,.cursorindexingignoreor.aiexclude?
If a file is sensitive and not excluded, an AI editor can index it and send it to the model — so veilcheck flags it. No code is executed, no network calls are made, no API key is needed. It's a single static binary.
It deliberately does not read .gitignore: AI editors may still index
git-ignored files, so .gitignore is not a substitute for .cursorignore.
go install github.com/jay-tank/veilcheck@latestOr build from source: go build -o veilcheck .
veilcheck # audit the current directory
veilcheck ./my-repo # audit a path
veilcheck --fix # print the .cursorignore lines to add
veilcheck --json # machine-readable output
veilcheck --strict # treat suspicious-name warnings as failures too- run: go run github.com/jay-tank/veilcheck@latest ./Exit codes: 0 clean · 1 a sensitive file is exposed · 2 usage error.
| Rule | Severity | What |
|---|---|---|
| VC001 | blocker | A sensitive file (by name/type or embedded secret) is not excluded from AI-editor context |
| VC002 | warning | A suspiciously-named file (secrets*, *.private, *.secret) is not excluded |
Warnings fail the run only under --strict.
--fix prints ready-to-paste ignore lines for every leaking file — root files
bare, nested files anchored with a leading / so nothing else is hidden by
accident:
$ veilcheck --fix
...
# Add these lines to .cursorignore to hide sensitive files from AI-editor indexing:
.env
/deploy/prod.pemSee examples/: a leaky-repo/ (no .cursorignore → exit 1) and a
safe-repo/ (same files, covered → exit 0). All secrets in the fixtures are
FAKE placeholders.
veilcheck is a heuristic, and honest about it:
- Classification is heuristic. Name/type/content rules can miss an oddly-named secret or over-flag a benign file. Suppress with an ignore entry.
- It checks coverage, not the live index. veilcheck verifies
.cursorignore/.aiexcludecoverage — it does not inspect the editor's actual index, nor its account-level privacy / "don't train on my code" / remote settings. A covered file can still be sent if you've configured the editor to ignore its own ignore file. .gitignoreis not a substitute. Git-ignored files may still be indexed; that's precisely why veilcheck doesn't count.gitignoreas protection.
It answers one question well — "which sensitive files could my AI editor send to the model right now?" — as a fast, offline gate.
MIT © Jay Tank