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

# Secrets Scanner

> Detect hardcoded credentials, exposed tokens, and OWASP security patterns in your codebase.

## Overview

The secrets scanner is ZenVeil's most comprehensive detector. It runs on `scan repo` and `scan github` targets and covers two categories:

1. **Credential patterns** — actual secrets that should never appear in source code
2. **Repository risk patterns** — OWASP anti-patterns that create security debt

## Credential patterns

These findings are always CRITICAL or HIGH severity. They indicate live credentials committed to source.

| Pattern            | Severity | Confidence | Description                                   |
| ------------------ | -------- | ---------- | --------------------------------------------- |
| AWS access key     | CRITICAL | 95%        | `AKIA` + 16 alphanumeric characters           |
| GitHub token       | CRITICAL | 95%        | `ghp_`, `gho_`, `ghu_`, `ghs_`, `ghr_` prefix |
| Private key block  | CRITICAL | 98%        | `-----BEGIN ... PRIVATE KEY-----`             |
| Hardcoded API key  | HIGH     | 80%        | `api_key = "..."`, `access_token = "..."`     |
| Hardcoded password | HIGH     | 75%        | `password = "..."`, `passwd = "..."`          |
| JWT token          | HIGH     | 85%        | Three base64url segments separated by `.`     |
| Slack token        | HIGH     | 90%        | `xoxb-`, `xoxa-`, `xoxp-`, `xoxr-`, `xoxs-`   |

### Example finding

```
ID:          ZG-A1B2C3
Severity:    CRITICAL
Title:       AWS access key
Scanner:     secrets
Category:    secrets
OWASP:       A02:2021 — Cryptographic Failures
Location:    src/config.js:14:23
Evidence:    AWS access key pattern matched; secret value redacted.
Confidence:  95%
Remediation: Revoke the AWS key, remove it from the repository, and
             load it from a secret manager or environment variable.
```

## Repository risk patterns

These findings surface OWASP anti-patterns that are common in AI-generated code. Severity ranges from MEDIUM to CRITICAL.

### Authentication & session management

| Pattern                                                     | Severity | OWASP              |
| ----------------------------------------------------------- | -------- | ------------------ |
| Predictable JWT signing secret (`changeme`, `secret`, etc.) | CRITICAL | A02:2021           |
| JWT signed inline with predictable secret                   | CRITICAL | A02:2021           |
| Token stored in `localStorage` or `sessionStorage`          | HIGH     | A02:2021, A07:2021 |
| Client-written cookie with token data                       | HIGH     | A02:2021           |
| Long-lived session token (365d, `never`, `0`)               | MEDIUM   | A07:2021           |
| Client-side-only logout                                     | MEDIUM   | A07:2021           |

### Authorization

| Pattern                                                | Severity | OWASP    |
| ------------------------------------------------------ | -------- | -------- |
| Client-side admin gate (`isAdmin`, `role === 'admin'`) | MEDIUM   | A01:2021 |
| Sensitive route without visible auth middleware        | HIGH     | A01:2021 |
| Object lookup by request-controlled ID (possible IDOR) | MEDIUM   | A01:2021 |

### Frontend exposure

| Pattern                                                 | Severity | OWASP    |
| ------------------------------------------------------- | -------- | -------- |
| Secret in `VITE_`, `NEXT_PUBLIC_`, `REACT_APP_` env var | HIGH     | A02:2021 |
| Open redirect using request parameters                  | HIGH     | A01:2021 |

### Infrastructure

| Pattern                                                   | Severity | OWASP    |
| --------------------------------------------------------- | -------- | -------- |
| Debug mode enabled (`DEBUG=True`, `NODE_ENV=development`) | MEDIUM   | A05:2021 |
| `USER root` in Dockerfile                                 | HIGH     | A05:2021 |
| Public database bind address                              | HIGH     | A05:2021 |
| Weak password hashing (MD5, SHA1)                         | HIGH     | A02:2021 |
| Low bcrypt cost factor (≤10)                              | MEDIUM   | A02:2021 |

### Dependencies

| Pattern                                          | Severity | OWASP    |
| ------------------------------------------------ | -------- | -------- |
| Install-time script in `package.json`            | MEDIUM   | A06:2021 |
| Unpinned Python dependency in `requirements.txt` | LOW      | A06:2021 |

## Environment file hygiene

The secrets scanner also checks:

* **`.env` file committed** (HIGH, 97% confidence) — any `.env`, `.env.local`, `.env.production`, etc. found in the repo
* **`.env` not in `.gitignore`** (MEDIUM, 93% confidence) — the `.gitignore` doesn't contain an `.env` exclusion pattern

```bash theme={null}
# Fix both with:
git rm --cached .env
echo ".env*" >> .gitignore
git commit -m "Remove .env from tracking and add to gitignore"
```

## Files scanned

The scanner traverses all files in the repository except:

* `node_modules/`, `.venv/`, `__pycache__/`, `.git/`
* Binary files (images, archives, compiled artifacts)
* Files > 1MB (unlikely to contain useful patterns)

## Context-aware severity

Test, fixture, mock, and example files are scanned by default — because real credentials are routinely committed there. Instead of ignoring these files and creating blind spots, ZenVeil detects findings in all files but **adjusts severity based on file context**.

### How it works

When a secret is found outside of production code, ZenVeil:

1. Detects it with the same confidence as a production finding
2. Downgrades the severity by one or two tiers
3. Appends `(test file)`, `(fixture file)`, or `(example file)` to the title
4. Labels the finding with a context badge in the output

### Severity downgrade table

| Original severity | In test/fixture/example file |
| ----------------- | ---------------------------- |
| CRITICAL          | → MEDIUM                     |
| HIGH              | → LOW                        |
| MEDIUM            | → LOW                        |
| LOW               | → LOW                        |

### Context classification

Files are classified by their path:

| Context      | Matched paths                                                                                                  |
| ------------ | -------------------------------------------------------------------------------------------------------------- |
| `production` | Everything not matched below — full severity                                                                   |
| `test`       | `tests/`, `test/`, `spec/`, `__tests__/`, `e2e/`, `integration/`, `unit/`, `*.test.*`, `*.spec.*`, `test_*.py` |
| `fixture`    | `fixtures/`, `mocks/`, `stubs/`, `fakes/`, `seeds/`, `factory/`, `testdata/`                                   |
| `example`    | `examples/`, `demos/`, `samples/`                                                                              |

### Example

```
# Production file → CRITICAL
ZG-A1B2  CRITICAL  prod     secrets   AWS access key           src/config.py:14

# Test file → downgraded to MEDIUM
ZG-C3D4  MEDIUM    test     secrets   AWS access key (test file)   tests/test_auth.py:8
```

To skip non-production files entirely, use the `--exclude-tests` flag:

```bash theme={null}
zenveil scan github owner/repo --exclude-tests
```

This is not recommended as the default — credentials in test history are still in your git history and still exploitable. See [Context-aware scanning](/docs/cli/scan#context-aware-scanning) for the full rationale.

## Avoiding false positives

All secret values in findings are **redacted** — ZenVeil never logs, stores, or transmits actual credential values.

To suppress a confirmed false positive:

```bash theme={null}
zenveil ignore ZG-A1B2C3 --reason "Test fixture — not a real key"
```

To record it for the feedback loop:

```bash theme={null}
zenveil feedback ZG-A1B2C3 false_positive
```
