Skill: theshadowrose/env-guard (version 1.0.2)

--- name: "EnvGuard Secret & Credential Scanner" description: "Scan repos and workspaces for leaked secrets. API keys in code, passwords in configs, tokens in logs. Catches them before they hit git." author: "@TheShadowRose" version: "1.0.2" tags: ["env-guard"] license: "MIT" --- # EnvGuard Secret & Credential Scanner Scan repos and workspaces for leaked secrets. API keys in code, passwords in configs, tokens in logs. Catches them before they hit git. --- Find leaked secrets before they reach production. ## Quick Scan ```bash node src/env-guard.js scan ./my-project ``` ## What It Finds | Secret Type | Pattern | |-------------|---------| | API Keys | `sk-...`, `AKIA...`, `ghp_...` | | Passwords | `password=`, `passwd:` | | Tokens | `token=`, `bearer ...` | | Private Keys | `-----BEGIN RSA PRIVATE KEY-----` | | Connection Strings | `mongodb://`, `postgres://` | | Webhook URLs | Discord webhooks, Slack webhooks | ## Features - **Custom patterns** — add your own secret patterns - **Allowlisting** — mark false positives to skip - **CI integration** — exit code 1 for pipeline gates ## Output ``` 🔴 SECRETS FOUND — 3 issues src/config.js:12 API key detected: sk-proj-...Tm4x (OpenAI) .env.backup:3 Database password in committed file logs/debug.log:445 Bearer token logged in plaintext ``` --- ## ⚠️ Disclaimer This software is provided "AS IS", without warranty of any kind, express or implied. **USE AT YOUR OWN RISK.** - The author(s) are NOT liable for any damages, losses, or consequences arising from the use or misuse of this software — including but not limited to financial loss, data loss, security breaches, business interruption, or any indirect/consequential damages. - This software does NOT constitute financial, legal, trading, or professional advice. - Users are solely responsible for evaluating whether this software is suitable for their use case, environment, and risk tolerance. - No guarantee is made regarding accuracy, reliability, completeness, or fitness for any particular purpose. - The author(s) are not responsible for how third parties use, modify, or distribute this software after purchase. By downloading, installing, or using this software, you acknowledge that you have read this disclaimer and agree to use the software entirely at your own risk. **DATA DISCLAIMER:** This software processes and stores data locally on your system. The author(s) are not responsible for data loss, corruption, or unauthorized access resulting from software bugs, system failures, or user error. Always maintain independent backups of important data. This software does not transmit data externally unless explicitly configured by the user. --- ## Support & Links | | | |---|---| | 🐛 **Bug Reports** | [REDACTED_SECRET] | | ☕ **Ko-fi** | [ko-fi.com/theshadowrose](https://ko-fi.com/theshadowrose) | | 🛒 **Gumroad** | [shadowyrose.gumroad.com](https://shadowyrose.gumroad.com) | | 🐦 **Twitter** | [@TheShadowyRose](https://twitter.com/TheShadowyRose) | | 🐙 **GitHub** | [github.com/TheShadowRose](https://github.com/TheShadowRose) | | 🧠 **PromptBase** | [promptbase.com/profile/shadowrose](https://promptbase.com/profile/shadowrose) | *Built with [OpenClaw](https://github.com/openclaw/openclaw) — thank you for making this possible.* --- 🛠️ **Need something custom?** Custom OpenClaw agents & skills starting at $500. If you can describe it, I can build it. → [Hire me on Fiverr](https://www.fiverr.com/s/jjmlZ0v)

path: LICENSE.md
content: MIT License

Copyright (c) 2026 Shadow Rose

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


path: README.md
content: # EnvGuard — Secret & Credential Scanner

Find leaked secrets before they reach production.

## Quick Scan

```bash
node src/env-guard.js scan ./my-project
```

## What It Finds

| Secret Type | Pattern |
|-------------|---------|
| API Keys | `sk-...`, `AKIA...`, `ghp_...` |
| Passwords | `password=`, `passwd:` |
| Tokens | `token=`, `bearer ...` |
| Private Keys | `-----BEGIN RSA PRIVATE KEY-----` |
| Connection Strings | `mongodb://`, `postgres://` |
| Webhook URLs | Discord webhooks, Slack webhooks |

## Features

- **Custom patterns** — add your own secret patterns
- **Allowlisting** — mark false positives to skip
- **CI integration** — exit code 1 for pipeline gates

## Output

```
🔴 SECRETS FOUND — 3 issues

src/config.js:12
  API key detected: sk-proj-...Tm4x (OpenAI)

.env.backup:3
  Database password in committed file

logs/debug.log:445
  Bearer token logged in plaintext
```
---

## ⚠️ Disclaimer

This software is provided "AS IS", without warranty of any kind, express or implied.

**USE AT YOUR OWN RISK.**

- The author(s) are NOT liable for any damages, losses, or consequences arising from 
  the use or misuse of this software — including but not limited to financial loss, 
  data loss, security breaches, business interruption, or any indirect/consequential damages.
- This software does NOT constitute financial, legal, trading, or professional advice.
- Users are solely responsible for evaluating whether this software is suitable for 
  their use case, environment, and risk tolerance.
- No guarantee is made regarding accuracy, reliability, completeness, or fitness 
  for any particular purpose.
- The author(s) are not responsible for how third parties use, modify, or distribute 
  this software after purchase.

By downloading, installing, or using this software, you acknowledge that you have read 
this disclaimer and agree to use the software entirely at your own risk.


**DATA DISCLAIMER:** This software processes and stores data locally on your system. 
The author(s) are not responsible for data loss, corruption, or unauthorized access 
resulting from software bugs, system failures, or user error. Always maintain 
independent backups of important data. This software does not transmit data externally 
unless explicitly configured by the user.

---

## Support & Links

| | |
|---|---|
| 🐛 **Bug Reports** | [REDACTED_SECRET] |
| ☕ **Ko-fi** | [ko-fi.com/theshadowrose](https://ko-fi.com/theshadowrose) |
| 🛒 **Gumroad** | [shadowyrose.gumroad.com](https://shadowyrose.gumroad.com) |
| 🐦 **Twitter** | [@TheShadowyRose](https://twitter.com/TheShadowyRose) |
| 🐙 **GitHub** | [github.com/TheShadowRose](https://github.com/TheShadowRose) |
| 🧠 **PromptBase** | [promptbase.com/profile/shadowrose](https://promptbase.com/profile/shadowrose) |

*Built with [OpenClaw](https://github.com/openclaw/openclaw) — thank you for making this possible.*

---

🛠️ **Need something custom?** Custom OpenClaw agents & skills starting at $500. If you can describe it, I can build it. → [Hire me on Fiverr](https://www.fiverr.com/s/jjmlZ0v)


path: src/env-guard.js
content: /**
 * EnvGuard — Secret & Credential Scanner
 * Scan files for leaked API keys, passwords, tokens, and secrets.
 * @author @TheShadowRose
 * @license MIT
 */

const fs = require('fs');
const path = require('path');

const DEFAULT_PATTERNS = [
  { name: 'OpenAI API Key', pattern: /sk-[a-zA-Z0-9]{20,}/, severity: 'critical' },
  { name: 'AWS Access Key', pattern: /AKIA[0-9A-Z]{16}/, severity: 'critical' },
  { name: 'GitHub Token', pattern: /ghp_[a-zA-Z0-9]{36}/, severity: 'critical' },
  { name: 'GitHub OAuth', pattern: /gho_[a-zA-Z0-9]{36}/, severity: 'critical' },
  { name: 'Anthropic API Key', pattern: /sk-ant-[a-zA-Z0-9\-_]{20,}/, severity: 'critical' },
  { name: 'Generic API Key', pattern: /api[_-]?key\s*[:=]\s*['"][a-zA-Z0-9]{16,}['"]/i, severity: 'high' },
  { name: 'Generic Secret', pattern: /secret\s*[:=]\s*['"][a-zA-Z0-9]{16,}['"]/i, severity: 'high' },
  { name: 'Generic Token', pattern: /token\s*[:=]\s*['"][a-zA-Z0-9]{16,}['"]/i, severity: 'high' },
  { name: 'Password in Config', pattern: /password\s*[:=]\s*['"][^'"]{4,}['"]/i, severity: 'high' },
  { name: 'Private Key', pattern: /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/, severity: 'critical' },
  { name: 'Connection String', pattern: /(mongodb|postgres|mysql|redis):\/\/[^\s'"]+/i, severity: 'high' },
  { name: 'Discord Webhook', pattern: /https:\/\/discord\.com\/api\/webhooks\/\d+\/[a-zA-Z0-9_-]+/, severity: 'high' },
  { name: 'Slack Webhook', pattern: /https:\/\/hooks\.slack\.com\/services\/[A-Z0-9]+\/[A-Z0-9]+\/[a-zA-Z0-9]+/, severity: 'high' },
  { name: 'Bearer Token', pattern: /bearer\s+[a-zA-Z0-9\-_.]{20,}/i, severity: 'high' },
  { name: 'JWT Token', pattern: /eyJ[a-zA-Z0-9\-_]+\.eyJ[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_.]+/, severity: 'medium' },
];

const DEFAULT_IGNORE = [
  'node_modules', '.git', 'dist', 'build', '__pycache__',
  '.jpg', '.png', '.gif', '.ico', '.svg', '.woff', '.ttf',
  '.exe', '.dll', '.so', '.dylib', '.zip', '.tar', '.gz'
];

class EnvGuard {
  constructor(options = {}) {
    this.patterns = options.patterns || DEFAULT_PATTERNS;
    this.ignoreDirs = options.ignoreDirs || DEFAULT_IGNORE;
    this.allowlist = options.allowlist || [];
    this.findings = [];
  }

  scan(targetPath) {
    this.findings = [];
    this._scanDir(path.resolve(targetPath));
    return this.report();
  }

  _scanDir(dirPath) {
    let entries;
    try { entries = fs.readdirSync(dirPath, { withFileTypes: true }); }
    catch { return; }

    for (const entry of entries) {
      const fullPath = path.join(dirPath, entry.name);
      
      if (entry.isDirectory()) {
        if (!this.ignoreDirs.includes(entry.name)) {
          this._scanDir(fullPath);
        }
        continue;
      }

      // Skip binary/image files
      const ext = path.extname(entry.name).toLowerCase();
      if (DEFAULT_IGNORE.some(i => i.startsWith('.') && ext === i)) continue;

      this._scanFile(fullPath);
    }
  }

  _scanFile(filePath) {
    let content;
    try { content = fs.readFileSync(filePath, 'utf8'); }
    catch { return; }

    const lines = content.split('\n');
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];
      for (const pat of this.patterns) {
        const match = line.match(pat.pattern);
        if (match) {
          const finding = {
            file: filePath,
            line: i + 1,
            type: pat.name,
            severity: pat.severity,
            snippet: this._redact(match[0]),
            raw: line.trim().substring(0, 120)
          };
          
          // Check allowlist
          const key = `${filePath}:${i + 1}:${pat.name}`;
          if (!this.allowlist.includes(key)) {
            this.findings.push(finding);
          }
        }
      }
    }
  }

  _redact(value) {
    if (value.length <= 8) return '***';
    return value.substring(0, 4) + '...' + value.substring(value.length - 4);
  }

  report() {
    const critical = this.findings.filter(f => f.severity === 'critical');
    const high = this.findings.filter(f => f.severity === 'high');
    const medium = this.findings.filter(f => f.severity === 'medium');

    return {
      clean: this.findings.length === 0,
      total: this.findings.length,
      critical: critical.length,
      high: high.length,
      medium: medium.length,
      findings: this.findings,
      summary: this.findings.length === 0
        ? '✅ No secrets found'
        : `🔴 ${this.findings.length} potential secrets found (${critical.length} critical, ${high.length} high, ${medium.length} medium)`
    };
  }

  addPattern(name, pattern, severity = 'high') {
    this.patterns.push({ name, pattern, severity });
    return this;
  }

  addAllowlist(entry) {
    this.allowlist.push(entry);
    return this;
  }
}

// CLI mode
if (require.main === module) {
  const target = process.argv[2] || '.';
  const guard = new EnvGuard();
  const report = guard.scan(target);
  
  console.log(`\n${report.summary}\n`);
  
  for (const f of report.findings) {
    const icon = f.severity === 'critical' ? '🔴' : f.severity === 'high' ? '🟡' : '🔵';
    console.log(`${icon} ${f.file}:${f.line}`);
    console.log(`   ${f.type}: ${f.snippet}`);
  }
  
  process.exit(report.clean ? 0 : 1);
}

module.exports = { EnvGuard };


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)