← All Posts

Building a Weekly Security Audit for My Side Projects

5 min readMarch 21, 2026
securityclaude-codeautomationai-toolsdeveloper-tools

Security Audit Dashboard
Security Audit Dashboard

I was scrolling Hacker News when I saw a thread about someone who got compromised through their self-hosted AI assistant. Prompt injection, exposed API keys, MCP servers phoning home to unknown URLs — the attack surface of an AI-powered dev setup is bigger than most of us realize.

I run 7+ side projects, a self-hosted n8n instance, a personal AI assistant, and about 60 Claude Code skills. Each one is a potential vector. And I had no systematic way to check if any of them were leaking secrets, serving stale data, or running compromised code.

That weekend, I built a security audit that runs every Monday morning. Here's what it checks, why, and what I've already caught.

The Attack Surface No One Talks About

When you're building with AI tools, your attack surface isn't just your code. It's every integration point.

Attack Surface — AI Builder Setup
YOUR CODE
.env files tracked in git
Hardcoded API keys
Public repos with secrets
npm vulnerabilities
YOUR AI TOOLS
MCP servers with unknown URLs
Skills with prompt injection
Plugins exfiltrating data
Overly broad permissions
YOUR CONTENT
Blog posts leaking credentials
Internal codenames in public content
Admin APIs without auth
Passwords in memory files
YOUR INFRA
Stale deployments serving old code
DB connections failing silently
Wrong git email blocking deploys
Exposed webhook endpoints

Traditional security advice focuses on the first quadrant — your code. But if you're running MCP servers, AI skills, and self-hosted automations, the other three quadrants are just as dangerous.

The 11-Point Audit

I built this as a Claude Code skill, so I can run /security-audit at the start of any session. It takes about 2 minutes and checks everything I care about.

Security Audit — 11 Checks
1
Secrets in Git
Scan tracked files for .env, .pem, credentials across all repos
CRITICAL
2
.gitignore Coverage
Verify every repo has .env* in .gitignore
IMPORTANT
3
Repo Visibility
Confirm sensitive repos are private on GitHub
CRITICAL
4
Public Repo Secrets Scan
Regex scan public repos for hardcoded API keys and tokens
CRITICAL
5
npm Vulnerabilities
Run npm audit on all Node.js projects
IMPORTANT
6
Live Site Health
HTTP status + DB health check on all deployed sites
HEALTH
7
Admin API Auth
Verify unauthenticated requests get 401
CRITICAL
8
Blog Content Secrets
Scan published content for leaked keys or internal codenames
CRITICAL
9
MCP Server Config
Review all MCP servers for unknown URLs or suspicious tokens
AI-SPECIFIC
10
Skills Injection Scan
Grep all skills for prompt override, persona hijack, and exfiltration patterns
AI-SPECIFIC
11
Git Email Config
Verify deploy-critical repos have the correct committer email
HEALTH

The first 8 checks are standard security hygiene that any developer should run. Checks 9 and 10 are what make this AI-specific — and they're the ones most people skip.

The AI-Specific Checks That Matter Most

MCP Server Audit

Every MCP server you connect to Claude Code is a trusted integration with access to your tools and context. My config connects to Google Workspace, Sheets, Gmail, Calendar, Notion, Slack, and n8n. Each one has env vars with API keys and OAuth tokens.

The audit enumerates every MCP server, logs its command or URL, and flags any env vars containing SECRET, KEY, TOKEN, or PASSWORD. If I see a server pointing to a domain I don't recognize, that's an immediate red flag.

import json
with open('.claude.json') as f:
    d = json.load(f)
for ctx in d.get('projects', {}).values():
    mcp = ctx.get('mcpServers', {})
    for name, cfg in mcp.items():
        cmd = cfg.get('command', cfg.get('url', 'N/A'))
        print(f'{name}: {cmd}')
        env = cfg.get('env', {})
        for k in env:
            if any(s in k.upper() for s in ['SECRET','KEY','TOKEN','PASSWORD']):
                print(f'  env: {k} (present)')

Skills Injection Scan

This is the one that keeps me up at night. Claude Code skills are markdown files that shape how the agent behaves. A malicious skill could include prompt injection — instructions to ignore previous rules, adopt a new persona, or silently exfiltrate data.

I scan all 60+ skills for three categories of patterns:

# Prompt override attempts
grep -rliE 'ignore (all |any )?(previous|prior|above) (instructions|prompts)' ~/.claude/skills/

# Stealth/exfiltration patterns
grep -rliE 'do not (tell|inform|show|reveal).*(user|human)|secretly|covertly' ~/.claude/skills/

# Suspicious external URLs (non-standard domains)
grep -rnoE 'https?://[a-z0-9.-]+\.[a-z]{2,}' ~/.claude/skills/ | \
  grep -vE 'github\.com|google\.com|anthropic\.com|vercel\.com|npmjs\.com' | \
  sort -u

Most matches are false positives — educational content about prompt injection, for example. But the scan gives me a manifest of every external URL my skills reference, and every file that touches sensitive language patterns. That visibility alone is worth the 30 seconds it takes to run.

What I've Actually Caught

In the first two weeks of running this audit:

Real Findings
CRITICAL
A public repo had an API key pattern in a config file — turned out to be a placeholder, but it matched the regex for Google API keys. Fixed by using a clearly-fake example key instead.
WARN
3 critical npm vulnerabilities in a project I hadn't touched in months — the transitive dependency tree had drifted.
WARN
An installed skill contained URLs pointing to domains I didn't recognize — legitimate (they were CDN endpoints for a UI library), but I wouldn't have known without the scan.
HEALTH
DB health check caught my site silently serving stale fallback data after a Turso connection string expired. Without the audit, I wouldn't have noticed for days.

None of these were catastrophic. That's the point. You run the audit so that small issues get caught before they become incidents.

Making It a Habit

The audit is a Claude Code skill, so the friction is near zero. I type /security-audit, it runs all 11 checks in about 2 minutes, and presents a summary table:

SECURITY & HEALTH AUDIT — 2026-03-17

| #  | Check                        | Status | Notes                          |
|----|------------------------------|--------|--------------------------------|
| 1  | Secrets in git               | PASS   |                                |
| 2  | .gitignore coverage          | PASS   |                                |
| 3  | Repo visibility              | PASS   |                                |
| 4  | Public repo secrets          | PASS   |                                |
| 5  | npm vulnerabilities          | WARN   | 1 critical in travel-map      |
| 6  | Live site health             | PASS   |                                |
| 7  | Admin API auth               | PASS   |                                |
| 8  | Blog content secrets         | PASS   |                                |
| 9  | MCP server config            | PASS   |                                |
| 10 | Skills injection scan        | PASS   |                                |
| 11 | Git email config             | PASS   |                                |

Overall: PASS (0 critical, 1 warning)

Green table on Monday morning. That's it. Move on with your week.

Build Your Own

You don't need my exact skill. The pattern is simple:

  1. List your repos. Which have secrets? Which are public?
  2. List your integrations. MCP servers, skills, plugins, webhooks. Where do they point?
  3. Write regex scans. API key patterns, credential patterns, injection patterns.
  4. Check your live sites. Are they up? Is the DB responding? Is auth enforced?
  5. Automate it. Make it a skill, a script, a GitHub Action — whatever makes you actually run it.

The whole thing is bash scripts and grep. No fancy tooling needed. The value isn't in the technology — it's in the discipline of checking every week.

What I'd Do Differently

If I were starting over, I'd add two more checks:

Dependency provenance — not just npm audit for known CVEs, but checking if any of my dependencies recently changed maintainers or had suspicious publish activity. Supply chain attacks are the new frontier.

Permission drift — I recently discovered I had 498 one-off permission rules in my Claude Code settings that were all silently overridden by a single global "Bash" permission. None of my carefully accumulated rules were actually doing anything. A periodic check for permission bloat and unintended escalation would have caught that months earlier.

Security isn't a feature you ship once. It's a habit you maintain. And for AI builders, the attack surface is wider than traditional development — so the habit needs to be wider too.