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.// 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
Detection
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
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
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
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
- awsKey: 'AKIAIOSFODNN7EXAMPLE',
+ awsKey: '<REDACTED_AWS_ACCESS_KEY>',
Fix: JWT secret (with AI)
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
# .env (never commit this)
JWT_SECRET=a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
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');
}
## 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
};
// 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,
});
zenveil scan repo .
# โ No findings. Exiting with code 0.