Awesome Go

Crenox

CategorySecurity
SubcategorySecurity
Stars31

Zero-dependency pre-commit secret scanner using Aho-Corasick for high-performance credentials leak detection

About Crenox

This large README is shown as a plain-text preview. Read the full README at the source

# Crenox — Statically Compiled Git Secret Scanner & Pre-Commit Hook

<!-- SEO: git secret scanner, pre-commit hook, gitleaks alternative, trufflehog alternative, gitguardian alternative, detect-secrets alternative, git-secrets alternative, betterleaks alternative, talisman git hook, credentials detector, api key detection, go security tool, devsecops, gitlab secret detection sast, sarif, on-premises secret scanner, air-gapped secret detection, فاحص أسرار, فحص الأسرار البرمجية, كشف تسريب المفاتيح, فحص مفاتيح API, بديل gitleaks, بديل trufflehog, بديل gitguardian -->

<div align="center">

<pre style="line-height: 1.15; font-size: min(1.1vw, 11px); white-space: pre; overflow-x: auto; font-family: monospace; border: none; background: transparent; padding: 0; margin: 0; display: inline-block; text-align: left;">
 ██████╗ ██████╗  ███████╗ ████╗  ██╗  ██████╗  ██╗  ██╗
██╔════╝ ██╔══██╗ ██╔════╝ ██╔██╗ ██║ ██╔═══██╗ ╚██╗██╔╝
██║      ██████╔╝ █████╗   ██║╚██╗██║ ██║   ██║  ╚███╔╝ 
██║      ██╔══██╗ ██╔══╝   ██║ ╚████║ ██║   ██║  ██╔██╗ 
╚██████╗ ██║  ██║ ███████╗ ██║  ╚███║ ╚██████╔╝ ██╔╝╚██╗
 ╚═════╝ ╚═╝  ╚═╝ ╚══════╝ ╚═╝   ╚══╝  ╚═════╝  ╚═╝  ╚═╝
</pre>

**Statically compiled Git pre-commit secret scanner and credentials detector written in Go.**

<p align="center">
  <a href="https://github.com/crenoxhq/crenox">
    <img src="https://img.shields.io/badge/Secured%20by-Crenox-E2E8F0?style=for-the-badge&logo=shield&logoColor=0F172A&labelColor=0F172A" alt="Secured by Crenox" height="38">
  </a>
</p>

[![Release](https://img.shields.io/github/v/release/crenoxhq/crenox?color=3c6382&logo=github&label=latest)](https://github.com/crenoxhq/crenox/releases)
[![Go Reference](https://pkg.go.dev/badge/github.com/crenoxhq/crenox/v2.svg)](https://pkg.go.dev/github.com/crenoxhq/crenox/v2)
[![GitHub Marketplace](https://img.shields.io/badge/Marketplace-Crenox-3c6382.svg?logo=github)](https://github.com/marketplace/actions/crenox-git-secrets-scanner)
[![Downloads](https://img.shields.io/github/downloads/crenoxhq/crenox/total?color=4b6584&logo=github)](https://github.com/crenoxhq/crenox/releases)

[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/16011/badge)](https://www.bestpractices.dev/projects/16011)
[![CI](https://github.com/crenoxhq/crenox/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/crenoxhq/crenox/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-AGPL_3.0-4b6584)](LICENSE)
[![Go Version](https://img.shields.io/badge/Go-1.22+-2f3542?logo=go)](https://go.dev)

[![Platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20macOS%20%7C%20Windows%20%7C%20Android%2FTermux-2f3542)](#installation)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
[![Stars](https://img.shields.io/github/stars/crenoxhq/crenox?style=flat&logo=github&color=3c6382)](https://github.com/crenoxhq/crenox/stargazers)

<br><br>

</div>

<p align="left">
<a href="https://www.producthunt.com/products/crenox-leak-secret-scanner?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-crenox-secret-scanner" target="_blank" rel="noopener noreferrer"><img alt="Crenox Secret Scanner - Context-aware Git secret scanner in Go | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1196224&amp;theme=neutral&amp;t=1784131078630"></a>
</p>

---

## What is Crenox?

**Crenox** is a statically compiled, zero-dependency Git pre-commit hook and credentials scanner written in Go. It automatically blocks commits of API keys, SSH private keys, cloud credentials, database connection strings, and other sensitive material before they are recorded in version control history.

It is an alternative to tools like **Gitleaks**, **TruffleHog**, and **git-secrets**, focusing on lower resource utilization and local workflow integration.

Crenox uses a **three-tier detection pipeline** designed for speed and false positive reduction:

| Tier | Engine | Purpose |
|------|--------|---------|
| 1 — PATTERN | Aho-Corasick automaton | Matches 135+ known secret signatures in O(n) time, zero allocations |
| 2 — ENTROPY | Shannon entropy analysis | Catches unknown secrets by measuring information density (with Log2 LUT acceleration) |
| 3 — CONTEXT | Context classifier | Suppresses false positives from comments, test files, container digests, and placeholders |

A finding must survive all three tiers before it is reported.

---

## Quick Start

**Install and protect your repository in under 60 seconds:**

```bash
# 1. Automatic One-Line Install (Linux, macOS, Termux)
curl -fsSL https://crenoxhq.github.io/crenox/install.sh | bash

# Or via Go:
# go install github.com/crenoxhq/crenox/v2/cmd/crenox@latest

# 2. Protect current repository (if skipped during installer)
crenox install

# 3. Verify — Crenox will now scan every commit automatically
git add . && git commit -m "test"
```

**Or scan any directory right now, without a hook:**

```bash
crenox scan --recursive ./src
```

That is all. No configuration file required. No runtime dependencies. Works on Linux, macOS, Windows, and Android/Termux.

---

## Crenox Pro

For engineering teams and organizations, **Crenox Pro** provides centralized policy management, audit logging, and fleet-wide pre-commit enforcement within private infrastructure.

https://crenoxhq.github.io/crenox/crenox-demo.mp4

> **[Enterprise Licensing & Specification →](https://crenoxhq.github.io/crenox/pro.html)** &bull; **[Watch Demonstration (MP4)](https://crenoxhq.github.io/crenox/crenox-demo.mp4)**

---

## Terminal Demo

```bash
asciinema play https://crenoxhq.github.io/crenox/demo.cast
```

![Crenox Demo](docs/demo.gif?v=2.1.11)

---

## Table of Contents

- [What is Crenox](#what-is-crenox)
- [Quick Start](#quick-start)
- [Crenox Pro](#crenox-pro)
- [Performance](#performance)
- [Why Crenox](#why-crenox)
- [Architecture](#architecture)
- [Signature Coverage](#signature-coverage)
- [Show Your Security Badge](#show-your-security-badge)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Output Reference](#output-reference)
- [False Positive Handling](#false-positive-handling)
- [In the Wild (Live Archive)](https://crenoxhq.github.io/crenox/wild.html)
- [Running Tests](#running-tests)
- [Contributing](#contributing)
- [License](#license)

---

## Performance

Measured on real-world repositories with Crenox against the most popular alternatives, on a standard **GitHub Actions Ubuntu cloud runner** — the same infrastructure used in real-world CI/CD pipelines.

<details open>
<summary>Filesystem Scan Results (Standard Mode Averages)</summary>

| Repository | Tool | Avg Scan Time (s) | Avg CPU Time (s) | Peak RAM (MB) | Findings |
| :--- | :--- | :---: | :---: | :---: | :---: |
| [sample_secrets](https://github.com/GitGuardian/sample_secrets) | **Crenox** | **0.0072 s** | **0.0095 s** | **17.7 MB** | **4** |
| | Gitleaks v8.18.2 | 0.0241 s | 0.0307 s | 22.7 MB | 1 |
| | Betterleaks v1.6.1 | 0.0944 s | 0.1219 s | 45.4 MB | 2 |
| [truffleHogRegexes](https://github.com/dxa4481/truffleHogRegexes) | **Crenox** | **0.0073 s** | **0.0105 s** | **18.0 MB** | **0** |
| | Gitleaks v8.18.2 | 0.0372 s | 0.0498 s | 21.2 MB | 1 |
| | Betterleaks v1.6.1 | 0.1189 s | 0.1613 s | 48.5 MB | 1 |
| [serverless-node-api-boilerplate](https://github.com/crenoxhq/serverless-node-api-boilerplate) | **Crenox** | **0.0074 s** | **0.0109 s** | **18.1 MB** | **6** |
| | Gitleaks v8.18.2 | 0.0271 s | 0.0393 s | 23.0 MB | 2 |
| | Betterleaks v1.6.1 | 0.2510 s | 0.4711 s | 66.1 MB | 2 |
| **large_file_test (10 MB)** | **Crenox** | **0.0111 s** | **0.0138 s** | **18.0 MB** | **0** |
| | Gitleaks v8.18.2 | 1.8080 s | 1.8326 s | 23.8 MB | 1 |
| | Betterleaks v1.6.1 | 0.7533 s | 0.8140 s | 73.0 MB | 2 |

</details>

<details>
<summary>Git History Scan Results (History Mode Averages)</summary>

| Repository | Tool | Avg Scan Time (s) | Avg CPU Time (s) | Peak RAM (MB) | Findings |
| :--- | :--- | :---: | :---: | :---: | :---: |
| [sample_secrets](https://github.com/GitGuardian/sample_secrets) | **Crenox** | **0.0096 s** | **0.0136 s** | **18.0 MB** | **9** |
| | Gitleaks v8.18.2 | 0.0285 s | 0.0384 s | 23.1 MB | 5 |
| | Betterleaks v1.6.1 | 0.2931 s | 0.5716 s | 67.5 MB | 6 |
| [truffleHogRegexes](https://github.com/dxa4481/truffleHogRegexes) | **Crenox** | **0.0131 s** | **0.0226 s** | **18.4 MB** | **3** |
| | Gitleaks v8.18.2 | 0.0425 s | 0.0595 s | 23.6 MB | 6 |
| | Betterleaks v1.6.1 | 0.1309 s | 0.2237 s | 49.8 MB | 8 |
| [serverless-node-api-boilerplate](https://github.com/crenoxhq/serverless-node-api-boilerplate) | **Crenox** | **0.0105 s** | **0.0159 s** | **18.1 MB** | **6** |
| | Gitleaks v8.18.2 | 0.0306 s | 0.0463 s | 21.4 MB | 2 |
| | Betterleaks v1.6.1 | 0.2457 s | 0.4333 s | 66.7 MB | 2 |
| **large_file_test (10 MB)** | **Crenox** | **0.0049 s** | **0.0051 s** | **13.6 MB** | **0** |
| | Gitleaks v8.18.2 | 0.0236 s | 0.0299 s | 23.2 MB | 0 |
| | Betterleaks v1.6.1 | 0.0320 s | 0.0394 s | 30.4 MB | 0 |

</details>

> **Transparent & Auditable** — These results were generated by an [open-source automated benchmark script](https://github.com/crenoxhq/serverless-node-api-boilerplate/blob/main/scripts/run_benchmark.py) running on a standard GitHub Actions Ubuntu cloud runner. The full methodology, tooling, and workflow configuration are publicly visible — results are triggered and verified by the maintainer on each release. [**View the latest benchmark run →**](https://github.com/crenoxhq/serverless-node-api-boilerplate/actions/workflows/benchmark.yml)

**Summary:**

| Metric | vs Gitleaks | vs Betterleaks |
|--------|-------------|---------------|
| **Speed** | **2.9x to 162x faster** | **6.5x to 67x faster** |
| **Memory** | **1.2x to 1.7x less RAM** | **2.2x to 4.1x less RAM** |
| **Recall (Accuracy)** | Finds 4x more secrets on sample_secrets (4 vs 1) | Finds critical multi-file secrets missed by Betterleaks |

---

## Why Crenox — Comparison (vs Gitleaks, TruffleHog, detect-secrets, Betterleaks)

| Feature | Crenox | Gitleaks | TruffleHog | detect-secrets | Betterleaks |
|---------|:--------:|:-----------:|:----------:|:--------------:|:--------------:|
| Statically compiled, zero runtime dependencies | + | + | + | — (Python) | + |
| ARM / Android / Termux native support | + | partial | partial | partial | partial |
| Aho-Corasick O(n) multi-pattern matching | + | + | + | — | + |
| Shannon entropy analysis | + | + | + | + | — |
| Token efficiency (BPE tokenizer) | — | — | — | — | + |
| Context-aware false-positive suppression | + | — | — | partial | — |
| BIP-39 seed phrase detection | + | — | — | — | — |
| Single-layer Base64 decoding | + | + | + | — | + |
| Concurrent file scanning | + | + | + | + | + |
| SARIF & GitLab SAST output formatting | + | + | — | — | + |
| Global hook installation | + | + | — | — | — |
| Custom user-defined signatures | + | + | + | + | + |
| OTA self-updating binary | + | — | + | — | — |

---

## Architecture

### Detection Pipeline

```
  git commit (staged changes)
         |
  [Git Interop — internal/git]
   ListStagedFiles()   →  git diff --cached --name-status
   GetStagedDiff()     →  git diff --cached -- <path>  (modified files, added lines only)
   GetStagedContent()  →  git show :<path>              (new files, full content)
         |
  [Pre-flight Filters]
   - Bounded streaming queue (size 1024) to keep memory footprint bounded under concurrent load
   - Early directory pruning: walks ignore excluded paths (e.g. node_modules, vendor) on the fly
   - Binary detection: null-byte scan of first 8 KB (isBinaryFileFast)
   - Extension exclusion: case-insensitive match
   - Path exclusion: filepath.Match glob patterns
   - File size cap: files > 10 MB skipped
         |
  [Tier 1 — Aho-Corasick Trie  —  internal/trie/trie.go]
   Built once at startup via trie.Build() — allocation-free DFA matching of 135+ signatures
   Case-insensitive O(n) scan using a branchless 256-byte toLower lookup table
   and sync.Pool-recycled 64 KB streaming buffers to cap heap memory to ~3 MB
   BIP-39 mnemonic detection: 12/15/18/21/24 words validated against 2048-word dictionary
   Single-layer Base64 decoding: re-feeds decoded value through trie (catches K8s secrets)
   Blob aggregation: 3+ consecutive high-entropy lines → single CRITICAL finding
         |
  [Tier 2 — Shannon Entropy  —  internal/entropy/entropy.go]
   Precomputed Log2 Look-Up Table (LUT) for O(1) symbol entropy arithmetic
   Single-pass candidate token extractor for Base64 and Hex character sets
   Base64 tokens: entropy >= entropy_threshold (default 4.5 bits/symbol)
   Hex tokens:    entropy >= threshold × (4.0 / 6.0), min floor 3.0
   Skips: tokens < min_secret_length (default 20), all-identical chars, Java-style identifiers
         |
  [Tier 3 — Context Filter  —  internal/context/context.go]
   Checks (in order): test file path → commented line → unquoted RHS in source → UUID → version string
                    → env var placeholder → config placeholder → variable name → short alpha token
   Only Real decisions are forwarded to the reporter
         |
  [Reporter  —  internal/reporter/reporter.go]
   pretty / plain         → stderr    (human-readable, ANSI color)
   json / sarif / gitlab  → stdout    (or directly to file if --output is used)
         |
  exit 0 (CLEAN)  |  exit 1 (BLOCKED)
```

<details>
<summary>Tier 1 — Aho-Corasick Pattern Matching (detailed)</summary>

**Source:** [`internal/trie/trie.go`](internal/trie/trie.go)

The automaton is built once at startup via `trie.Build(sigs)` and shared across all goroutines without locks. `Automaton.Search` performs zero heap allocations on the hot path.

Construction is two-phase:
1. All signature prefixes are inserted into a trie with lowercased keys.
2. BFS computes failure links and merges output sets so overlapping prefixes (e.g. `sk-` and `sk-proj-`) are both reported in one pass.

The scanner applies additional logic on top of the raw trie results:
- **BIP-39 mnemonics** — line is tested for 12/15/18/21/24 space-separated words, all validated against `bip39.go`.
- **Single-layer Base64 decoding** — extracted values are decoded and re-fed through the trie to catch masked secrets (e.g. Kubernetes Secret manifests).
- **Blob aggregation** — 3+ consecutive lines of the same entropy class are collapsed into one `CRITICAL` finding (`massive-base64-blob` / `massive-hex-blob`) to prevent alert fatigue.
- **Same-Line & Cross-Signature Deduplication** — preserves distinct secrets occurring on the same line without overwriting, while upgrading lower-priority matches when a higher-severity signature covers the exact same token.
- **Tier 1 Precedence over Entropy** — tokens already matched by specific Tier 1 pattern rules suppress redundant Tier 2 Shannon entropy alerts on the same line.

</details>

<details>
<summary>Tier 2 — Shannon Entropy Analysis (detailed)</summary>

**Source:** [`internal/entropy/entropy.go`](internal/entropy/entropy.go)

```
H(X) = - sum over i of P(xi) * log2(P(xi))
```

| Score | Meaning |
|-------|---------|
| 0.0 | All bytes identical |
| ~3.5 | English prose |
| ~5.5 – 6.5 | Cryptographically random Base64 secret |
| 8.0 | Perfectly uniform 256-symbol distribution |

Crenox extracts two token classes per line:
- **Base64 tokens** — runs of `A-Za-z0-9+/=_-`; entropy must exceed `entropy_threshold` (default 4.5).
- **Hex tokens** — runs of `0-9a-fA-F`; must be even-length if short (< 32 characters) to filter out arbitrary non-secret hex strings; threshold is scaled: `entropy_threshold × (4.0 / 6.0)`, floor 3.0.

Pre-filters applied before entropy computation: Java-style identifiers (all letters/dots/underscores) and all-identical-character tokens are discarded.

</details>

<details>
<summary>Tier 3 — Context-Aware Filtering (detailed)</summary>

**Source:** [`internal/context/context.go`](internal/context/context.go)

| Decision | Condition |
|----------|-----------|
| `Real` | None of the suppression checks matched |
| `SafeComment` | Line begins with `//` `#` `*` `/*` `<!--` `--` `;` `%` `!` |
| `SafeTestFile` | Path ends with `_test.go` `_spec.rb` `.test.js` `.spec.ts` `.md` `.rst` `_test.py` `conftest.py`, starts with `test_` (`.py`), begins with `test-`, or contains directory: `test` `tests` `testdata` `fixtures` `__tests__` `__mocks__` `mock` `mocks` `sample` `samples` `docs` `doc` |
| `SafeVariableName` | Variable name (left of `=` / `:=`) contains: `dummy` `fake` `mock` `placeholder` `sample` `fixture` `stub` `lorem` `foobar` `your_` `your-` `insert_` `replace_` `changeme` `redacted` `sanitized` `censored`, or variable name matches assigned value (self-assignment) |
| `SafePlaceholder` | Token matches `$VAR`, `${VAR}`, `<...>`, `[[...]]`, `{{...}}`, `${{...}}`, redacted Bearer values (`Bearer <redacted>`), framework schema casts (`nullable|string`, `encrypted`), or Mozilla SOPS encrypted blocks (`ENC[<ALGO>,data:...]`) and Age recipient public keys (`age1...`) |
| `SafeUUID` | Token matches UUID v4 pattern `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` |
| `SafeVersionString` | Token begins with `digit.digit.digit` or consists of pure numeric sequences |
| `SafeSourceRHS` | Token on RHS of assignment in programming source files is bare/unquoted (e.g. Go struct types, function calls) |

The scanner also rejects tokens that match a `printf`-style format verb, are identical to their signature prefix, contain regex metacharacters, or (for short prefixes ≤ 3 bytes) are pure PascalCase/CamelCase with no special characters.

</details>

### Inline Suppression

Place `crenox:ignore` on the flagged line or the preceding comment line:

```go
// crenox:ignore
apiKey := "sk_live_example_for_documentation"

apiKey := "sk_live_example_for_documentation" // crenox:ignore
```

```bash
# crenox:ignore
STRIPE_KEY="sk_live_example"
```

```html
<!-- crenox:ignore -->
<secret>sk-ant-api03-documented-example</secret>
```

A same-line annotation suppresses only that line. A comment-line annotation suppresses the immediately following line.

---

## Signature Coverage

<details>
<summary>View all builtin signatures</summary>

| Category | Signatures |
|----------|-----------|
| **AI & ML Platforms** | OpenAI (`sk-`, `sk-proj-`), DeepSeek (`sk-`), Anthropic (`sk-ant-`), OpenRouter (`sk-or-v1-`), Cohere (`co_`), Together AI (`tog_`), Mistral AI (`mis_`), Groq (`gsk_`), Replicate (`r8_`), Resend (`re_`), Perplexity (`pplx-`), Fireworks AI (`fw_`), LangSmith (`lsv2_`), HuggingFace (`hf_`) |
| **Cloud Databases & Services** | Alibaba Cloud AccessKey ID (`LTAI`), Azure Storage Account Key, Doppler (`dp.st.`, `dp.pt.`, `dp.sa.`), Supabase (`sb_publishable_`, `sb_secret_`), Turso (`fn_`), Tailscale (`tskey-auth-`, `tskey-api-`), Clerk (`clerk_`), Neon (`npg_`), PlanetScale (`pscale_pw_`, `pscale_tkn_`), Terraform Cloud (`atlasv1`) |
| **DevSecOps & Analytics** | Grafana Cloud Token (`glc_`), Infracost API Key (`ico-`), Datadog (`ddp_`), PostHog (`phx_`, `phs_`, `pha_`), Linear (`lin_api_`), Sentry (`sntry_`), SonarQube (`squ_`), Snyk (`snyk_`), Pulumi (`pul-`), Databricks (`dapi`), Svix Webhook (`whsec_`) |
| **Social & Messaging** | Telegram Bot API Token (`bot<id>:<hash>`), Discord Webhook (`https://discord.com/api/webhooks/`), Slack Bot (`xoxb-`), User (`xoxp-`), Workspace (`xoxa-`), Webhook (`https://hooks.slack.com/services/`) |
| **GitHub** | Classic PAT (`ghp_`), OAuth (`gho_`), User-to-Server (`ghu_`), App Installation (`ghs_` - classic & JWT), Refresh (`ghr_`), Fine-grained PAT (`github_pat_`), Environment tokens (`GITHUB_TOKEN`, `_GITHUB_TOKEN`) |
| **Heroku** | API Key (`HEROKU_API_KEY`), OAuth Token (`heroku_oauth_token`) |
| **GitLab** | Personal Access Token (`glpat-`), Pipeline Trigger (`glptt-`), Runner Registration (`GR1348941`), Runner Token (`glrt-`) |
| **Postman** | API Key (`PMAK-`) |

Frequently Asked Questions

What is Crenox?

Crenox is a Security library for the Go programming language. Zero-dependency pre-commit secret scanner using Aho-Corasick for high-performance credentials leak detection

How do I install Crenox?

Install Crenox with the Go module system using `go get crenoxhq/crenox`. Check the repository for the current installation instructions.

What category does Crenox belong to?

Crenox is listed under Security, specifically Security.

← Back to Security