> ## 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.

# Example: Secret Detection

> A real-world walkthrough of ZenVeil detecting and remediating leaked credentials.

## Scenario

A developer used GitHub Copilot to generate a Node.js authentication module. The AI-generated code hardcoded credentials that were committed and pushed before anyone noticed.

```javascript theme={null}
// auth/config.js — generated by AI assistant
const config = {
  jwtSecret: 'supersecret',           // CRITICAL: predictable JWT secret
  awsKey: 'AKIAIOSFODNN7EXAMPLE',     // CRITICAL: AWS access key
  awsSecret: 'wJalrXUtnFEMI/K7...',  // HIGH: hardcoded AWS secret
  dbPassword: 'admin123',             // HIGH: hardcoded password
  sessionDuration: '365d',            // HIGH: year-long sessions
};

// Store JWT in localStorage after login
localStorage.setItem('auth_jwt', generateToken(user));  // HIGH: XSS exposure
```

Six vulnerabilities in nine lines. All introduced by an AI assistant following common patterns from its training data.

## Detection

```bash theme={null}
zenveil scan repo .
```

```
╭──────────────────────────────────────────────────────────────────────╮
│  ZenVeil Security Scan                                               │
│  Target: /home/user/node-auth  ·  Scanners: secrets, supply_chain   │
│  Duration: 1.2s                                                      │
╰──────────────────────────────────────────────────────────────────────╯

┌──────────┬──────────┬──────────┬────────────────────────────────────────┬──────────────────────────┐
│ ID       │ Severity │ Scanner  │ Title                                  │ Location                 │
├──────────┼──────────┼──────────┼────────────────────────────────────────┼──────────────────────────┤
│ ZG-A1B2  │ CRITICAL │ secrets  │ AWS access key                         │ auth/config.js:4         │
│ ZG-C3D4  │ CRITICAL │ secrets  │ Predictable JWT signing secret         │ auth/config.js:3         │
│ ZG-E5F6  │ HIGH     │ secrets  │ Hardcoded API key assignment           │ auth/config.js:5         │
│ ZG-G7H8  │ HIGH     │ secrets  │ Hardcoded password assignment          │ auth/config.js:6         │
│ ZG-I9J0  │ HIGH     │ secrets  │ Token stored in browser storage        │ auth/login.js:47         │
│ ZG-K1L2  │ HIGH     │ secrets  │ Long-lived session token               │ auth/config.js:7         │
└──────────┴──────────┴──────────┴────────────────────────────────────────┴──────────────────────────┘

6 finding(s) · CRITICAL: 2 · HIGH: 4

Exiting with code 1 (CRITICAL/HIGH findings present)
```

## Triage

```bash theme={null}
zenveil triage
```

```
Triaging 6 finding(s)…

PRIORITY ORDER (highest risk first)
════════════════════════════════════

1. ZG-A1B2 — AWS access key [CRITICAL]
   ⚠ IMMEDIATE ACTION REQUIRED
   An active AWS access key in source code is a live credential exposure.
   Automated bots scan GitHub continuously for this exact pattern (AKIA prefix).
   If this was ever pushed to a remote repository, assume it's compromised.

   Effort: 15 minutes
   Action:
   1. Revoke at https://console.aws.amazon.com/iam → Users → Security credentials
   2. git rm --cached auth/config.js
   3. git filter-branch or BFG to purge from history if committed
   4. Replace with: process.env.AWS_ACCESS_KEY_ID

2. ZG-C3D4 — Predictable JWT signing secret [CRITICAL]
   Any JWT signed with 'supersecret' can be forged by an attacker.
   Run: node -e "require('jsonwebtoken').sign({admin:true}, 'supersecret')"
   → Any attacker can mint admin tokens.

   Effort: 30 minutes (must invalidate all existing sessions)
   Action: Replace with crypto.randomBytes(64).toString('hex'), store in secrets manager

[... continues for all 6 findings ...]
```

## AI explanation

```bash theme={null}
zenveil explain ZG-A1B2
```

```
Explaining ZG-A1B2: AWS access key

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

What this is:
An AWS access key starting with 'AKIA' was found committed at
auth/config.js:4. This is a live AWS credential — the AKIA prefix
is a signature that AWS uses for long-lived access keys.

Why it's critical:
AWS access keys have no expiry by default and grant API-level access
to every AWS service the associated IAM user can access. Within minutes
of being committed to a public or semi-public repository, automated
scanners (GitGuardian, TruffleHog, and numerous threat actor tools)
will find and test this key.

Real-world consequence:
In 2023, a startup's AWS bill jumped from $10/month to $49,000 in 48
hours after an access key was committed to GitHub. The attacker spun up
GPU instances for crypto mining. AWS may not waive these charges.

OWASP: A02:2021 — Cryptographic Failures
Confidence: 95%
```

## Auto-fix: secret redaction PR

```bash theme={null}
zenveil fix ZG-A1B2 --auto-pr --repo owner/node-auth
```

```
Applying redaction directly (no API key needed).

Opened pull request: https://github.com/owner/node-auth/pull/23

PR title: [ZenVeil] Redact AWS access key (ZG-A1B2)
PR description:
  ZenVeil detected an AWS access key at auth/config.js:4.

  This PR redacts the value with <REDACTED_AWS_ACCESS_KEY>.

  IMPORTANT: The key must also be revoked in the AWS IAM console:
  https://console.aws.amazon.com/iam

  Finding ID: ZG-A1B2 · Severity: CRITICAL · OWASP: A02:2021
```

The PR applies this diff:

```diff theme={null}
- awsKey: 'AKIAIOSFODNN7EXAMPLE',
+ awsKey: '<REDACTED_AWS_ACCESS_KEY>',
```

## Fix: JWT secret (with AI)

```bash theme={null}
zenveil fix ZG-C3D4
```

````
Generating fix for ZG-C3D4: Predictable JWT signing secret

The JWT signing secret 'supersecret' at auth/config.js:3 is trivially
guessable. Any attacker who knows you're using JWT can forge tokens.

Here's the fix:

**Step 1: Generate a strong secret**

```bash
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
# → a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
````

**Step 2: Store in environment**

```bash theme={null}
# .env (never commit this)
JWT_SECRET=a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
```

**Step 3: Load at runtime**

```javascript theme={null}
const config = {
  jwtSecret: process.env.JWT_SECRET,  // Load from environment
  // ... other config
};

// Validate at startup
if (!config.jwtSecret || config.jwtSecret.length < 32) {
  throw new Error('JWT_SECRET must be at least 32 characters');
}
```

**Step 4: Invalidate existing tokens**

Since the old secret is compromised, you must invalidate all tokens
signed with it. The simplest approach is to change the secret and
require all users to log in again.

````

## Final state after remediation

After applying all fixes:

```javascript
// auth/config.js — after remediation
const config = {
  jwtSecret: process.env.JWT_SECRET,           // Strong, from env
  awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID, // From env/secrets manager
  awsSecretKey: process.env.AWS_SECRET_ACCESS_KEY,
  dbPassword: process.env.DB_PASSWORD,         // From env
  sessionDuration: '1h',                        // Reasonable lifetime
};
````

```javascript theme={null}
// auth/login.js — after remediation
// Removed: localStorage.setItem('auth_jwt', token)
// Replaced with server-side httpOnly cookie:
res.cookie('session', token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 3600000,
});
```

```bash theme={null}
zenveil scan repo .
# ✓ No findings. Exiting with code 0.
```
