> ## Documentation Index
> Fetch the complete documentation index at: https://envtrap.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Secret Detection

> How envtrap loads secrets from the environment, filters candidates, and detects their presence across all interception channels.

## Overview

envtrap's detection engine has two stages:

1. **Startup**: Load active secret candidates from the environment
2. **Runtime**: Scan intercepted content for exact matches of those candidates

***

## Stage 1 — Loading Active Secrets

When `envtrap run` starts, it builds an **in-memory secret registry** by scanning two sources:

### Source 1: `process.env`

Every environment variable present in the current shell is evaluated. Variables in a built-in blocklist of non-sensitive system variables are skipped automatically:

```
PATH, HOME, USER, SHELL, PWD, LANG, TERM, SHLVL, LOGNAME, MAIL, HOSTNAME,
HISTCONTROL, NODE_ENV, NODE_OPTIONS, EDITOR, DISPLAY, OLDPWD, XDG_* ...
```

For each remaining variable, the **value** is tested against the `looksLikeSecret` gate (see below).

### Source 2: `.env` file

If a `.env` file exists (or a custom path was provided via `--env-file`), it is parsed with `dotenv`. Variables that are **already loaded from `process.env`** are not duplicated — `process.env` takes precedence.

***

## Stage 2 — The `looksLikeSecret` Gate

Every candidate value must pass this filter before being registered:

```
                      Value from env / .env
                              │
              ┌───────────────▼───────────────┐
              │  Length ≥ minLength (def: 12) │
              └───────────────┬───────────────┘
                         fail │ pass
                         drop ▼
              ┌───────────────────────────────┐
              │  Matches deterministic regex? │  ──── yes ──▶ REGISTER
              └───────────────┬───────────────┘
                         no   │
                              ▼
              ┌───────────────────────────────┐
              │  Shannon entropy ≥ threshold  │  ──── yes ──▶ REGISTER
              │       (def: 3.5)              │
              └───────────────┬───────────────┘
                         no   │
                              ▼
                           DROP
```

***

## Built-in Deterministic Patterns

These patterns **always match** regardless of entropy score. They are compiled once at startup:

| Provider                     | Pattern                                          | Example                |
| ---------------------------- | ------------------------------------------------ | ---------------------- |
| Stripe                       | `sk_live_` or `sk_test_` + 24+ alphanumerics     | `sk_live_51Nz...`      |
| AWS Access Key ID            | `AKIA[0-9A-Z]{16}`                               | `AKIAIOSFODNN7EXAMPLE` |
| GitHub Personal Access Token | `ghp_[a-zA-Z0-9]{36}`                            | `ghp_abc123...`        |
| Generic Bearer Token         | `Bearer\s+[a-zA-Z0-9\-._~+/]{20,}`               | `Bearer eyJ...`        |
| SendGrid API Key             | `SG\.[a-zA-Z0-9\-_]{22}\.[a-zA-Z0-9\-_]{43}`     | `SG.xxx.yyy`           |
| Slack Bot Token              | `xoxb-[0-9]{11,13}-[0-9]{11,13}-[a-zA-Z0-9]{24}` | `xoxb-123-456-...`     |

***

## Shannon Entropy Analysis

Shannon entropy measures **character randomness** — the more evenly distributed the characters, the higher the score (range 0 to 8 bits per character).

| String                | Entropy | Classification                   |
| --------------------- | ------- | -------------------------------- |
| `hello world`         | ≈ 2.8   | Low — normal text                |
| `user_john_doe`       | ≈ 3.1   | Low — human-readable             |
| `db_prod_2024`        | ≈ 3.2   | Low — drops below threshold      |
| `aB3!kR9mNq2Xp7v`     | ≈ 4.1   | Medium — flagged                 |
| `ghp_xyz012345abc...` | ≈ 5.8   | High — matches pattern + entropy |

Configure the entropy gate in `envtrap.json`:

```json theme={null}
{
  "entropy": {
    "threshold": 3.5,
    "minLength": 12
  }
}
```

| Field       | Type     | Default | Description                                                     |
| ----------- | -------- | ------- | --------------------------------------------------------------- |
| `threshold` | `number` | `3.5`   | Shannon entropy score (0–8) a value must reach to be registered |
| `minLength` | `number` | `12`    | Minimum character length — shorter strings are always dropped   |

<Tip>
  Raise `threshold` to `4.0`–`4.5` in environments with many short config values to reduce false positives. Lower it only if you need to protect short secrets.
</Tip>

***

## Runtime Scanning

During execution, every intercepted payload is scanned for **exact substring matches** of all registered secret values. There are no regex scans at runtime — only direct string inclusion checks. This makes scanning extremely fast even for large payloads.

### 1 MB Backpressure Cap

To protect the Node.js event loop, content chunks larger than **1 MB** are clamped — only the first 1 MB is scanned. Secrets almost always appear at the beginning of HTTP headers, log lines, or JSON payloads.

### TTL Deduplication Cache

To prevent alert flooding, duplicate detections of the same `secret + channel` combination within a **1.5-second window** are silently suppressed. Only the first occurrence within the window triggers an alert and is recorded.

***

## Secret Fingerprinting (AI-Safe Redaction)

envtrap **never logs the raw value** of a secret. Instead, it prints a SHA-256 fingerprint:

```
  Secret:  STRIPE_SECRET_KEY  (source: env)
  Value:   [SHA256:baf2ae5634...]
  Channel: 🌐  NETWORK
```

This means:

* Terminal output is safe to share or paste into AI coding tools
* The fingerprint uniquely identifies the secret without exposing it
* Consistent hashing allows you to correlate the same secret across multiple channels

***

## Leak Report File

After the process exits, envtrap writes `.envtrap-report.json` to the current working directory:

```json theme={null}
[
  {
    "secretName": "STRIPE_SECRET_KEY",
    "source": "env",
    "channel": "network",
    "context": "Outbound HTTPS Request Audited:\n  Destination Host: api.stripe.com\n  ...",
    "sha256": "baf2ae563873...",
    "timestamp": 1781335024545
  }
]
```

| Field        | Description                                                  |
| ------------ | ------------------------------------------------------------ |
| `secretName` | The environment variable key name                            |
| `source`     | `"env"` (from `process.env`) or `"file"` (from `.env` file)  |
| `channel`    | Which interception channel detected the leak                 |
| `context`    | A sanitized snippet of the content where the secret appeared |
| `sha256`     | Full SHA-256 hex digest of the secret value                  |
| `timestamp`  | Unix millisecond timestamp of detection                      |
