| Crates.io | gremlh |
| lib.rs | gremlh |
| version | 0.3.0 |
| created_at | 2025-11-26 17:54:42.793857+00 |
| updated_at | 2025-12-10 19:57:27.910511+00 |
| description | A CLI tool to find and fix invisible 'gremlin' characters (homoglyphs, zero-width spaces, Bidi overrides) in source code. |
| homepage | |
| repository | https://github.com/boorboor/gremlh |
| max_upload_size | |
| id | 1951939 |
| size | 74,833 |
gremlh is a blazing fast, multi-threaded CLI tool designed to hunt down and sanitize "gremlin" characters in your source code.
It identifies invisible characters, zero-width spaces, homoglyphs, and potential security risks (such as Trojan Source attacks) that can cause compilation errors, syntax issues, or confusing bugs.
\u202A - \u202E) used in supply-chain attacks.ignore crate (the same engine used by ripgrep) for maximum speed..gitignore rules.cargo install gremlh
Download pre-built binaries for Linux, macOS, and Windows from the GitHub Releases page.
brew tap boorboor/gremlh
brew install gremlh
Recursively scans the current directory. Prints issues to stderr and exits with code 1 if gremlins are found.
gremlh
# Or specify a path
gremlh ./src
Example Output:
src/main.rs:10:45: found "" (Zero Width Space)
src/legacy.js:2:15: found "“" (Smart Double Quote)
src/security.go:5:1: found "" (Bidirectional Text Override)
--write)Automatically cleans files in-place.
gremlh --write
What gets fixed?
“ → "\u00A0 → (Space)Great for scripting or single-file processing.
cat dirty_file.txt | gremlh > clean_file.txt
| Flag | Short | Description |
|---|---|---|
--write |
-w |
Overwrite files in place with fixed content. |
--verbose |
-v |
Show detailed processing info (files scanned, binary skips). |
--no-ignore |
Ignore .gitignore and scan everything. |
|
--hidden |
Search hidden files and directories (e.g., .env). |
|
--threads |
-j |
Number of threads to use (defaults to CPU count). |
gremlh provides a native GitHub Action. Add this to your workflow to fail builds when gremlins are detected, or automatically fix them.
steps:
- uses: actions/checkout@v4
- name: Gremlin Hunter
uses: boorboor/gremlh@v0.1.0
with:
path: 'src/' # Optional: defaults to '.'
write: 'false' # Optional: set to 'true' to fix files
verbose: 'true' # Optional: show scanned files
# no-ignore: 'true' # Optional: ignore .gitignore
# hidden: 'true' # Optional: scan hidden files
Add this to your .pre-commit-config.yaml. We provide two hooks: one for checking, and one for auto-fixing.
- repo: [https://github.com/boorboor/gremlh](https://github.com/boorboor/gremlh)
rev: v0.1.0
hooks:
- id: gremlh # Fail on detection
# OR
- id: gremlh-fix # Auto-fix on commit
Auto-fix on save (add to your init.vim or .vimrc):
augroup GremlinKiller
autocmd!
autocmd BufWritePre *.rs,*.js,*.py silent! %!gremlh 2>/dev/null
augroup END
| Category | Description | Example | Action (--write) |
|---|---|---|---|
| Security | Trojan Source Bidi Overrides | \u202A |
Remove |
| Invisibles | Zero Width Space, Joiners | \u200B |
Remove |
| Whitespace | Non-breaking spaces | \u00A0 |
Replace with Space |
| Quotes | Smart/Curled Quotes | “ ” |
Replace with ASCII " |
| Homoglyphs | Greek Question Mark | ; |
Replace with ; |
| Control | Non-whitespace control chars | \x07 |
Remove |
We welcome contributions! Please see CONTRIBUTING.md for details on how to set up the environment and add new gremlin definitions.
cargo install prekprek installprek run --all-filesThis project is licensed under the Apache-2.0 License.