codebase-audit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited codebase-audit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This is the skill that binds the others together. Most engagement value from a security review comes from the auditor's process, not from any single check. A junior auditor with a great tool produces a noisy report; a senior auditor with grep and a methodology finds the things that matter.
This skill is the methodology. It walks the audit from "I just got SSH access / a repo URL" through to "here's the prioritized report with owners and deadlines." It cross-links into every hardening skill in this repo as the deep-dive material per finding class.
The most common reason audits fail is the auditor trying to look at everything. Scope discipline is the difference between a useful report and a 300-page document nobody reads.
Before starting, write down:
Without these five answers, do not start. Time spent here saves three times that later.
The goal of the first 30 minutes is orientation, not findings. Build a mental model of the system. Findings come later.
# What language(s), what framework(s)?
cd <repo>
ls -la
cat README.md
find . -name 'package.json' -not -path '*/node_modules/*' | head -5
find . -name 'requirements*.txt' -o -name 'pyproject.toml' -o -name 'Gemfile' -o -name 'go.mod' -o -name 'Cargo.toml' 2>/dev/nullAnswer in writing (in your notes, not yet the report):
If you cannot answer one of these from a 30-minute look, that's already a finding.
Now enumerate everything that matters.
git log --oneline | head -20
git log --all --format='%aN' | sort -u # who has committed
git tag # release cadence
git remote -v # where is it published
ls -la .github/ # workflows, codeowners# Next.js — App Router routes
find app -name 'route.ts' -o -name 'route.js' -o -name 'page.tsx' 2>/dev/null
# Next.js — Pages Router API routes
find pages/api 2>/dev/null
# Express
grep -rE "app\.(get|post|put|delete|patch|use)\(" src 2>/dev/null
grep -rE "router\.(get|post|put|delete|patch)\(" src 2>/dev/null
# Server Actions (Next.js)
grep -rln "'use server'" app 2>/dev/null
# WordPress — REST endpoints
grep -rE "register_rest_route" wp-content/ 2>/dev/null
# OpenAPI / Swagger if present
find . \( -name 'openapi.yaml' -o -name 'openapi.json' -o -name 'swagger.*' \) 2>/dev/nullBuild a list of every entry point. For each, you'll later answer "is auth checked? is input validated?"
cat package.json | jq '.dependencies, .devDependencies'
wc -l package-lock.json # rough sense of transitive surface
find . -name 'node_modules' -prune -o -name 'package.json' -print | wc -lfind . \( -name '*.tf' -o -name 'Dockerfile*' -o -name 'docker-compose*' -o -name 'k8s*.yaml' \) -not -path '*/node_modules/*' 2>/dev/null
ls .github/workflows/ 2>/dev/null# Database connection strings — environment variables only, never hardcoded
grep -rE 'DATABASE_URL|MONGO_URL|REDIS_URL|postgres://|mongodb://' --include='*.{js,ts,py,rb,go,env,yml,yaml}' . 2>/dev/null | grep -v node_modules
# File storage paths
grep -rE 'multer|formidable|busboy|fs\.write|writeFile|S3|R2|Bucket' --include='*.{js,ts}' . 2>/dev/null | grep -v node_modules | head -20Run automated tools early, parse their output later. The tools give you a haystack of candidates; the manual review (Step 4–6) figures out which are real.
# Semgrep — fast, language-aware, good default rules
brew install semgrep
semgrep --config=auto --json -o /tmp/semgrep.json . 2>/dev/null
semgrep --config=auto . 2>&1 | grep -E '(WARNING|ERROR|^Findings:|^\s*severity:)' | head -30
# More targeted — security-focused rules only
semgrep --config=p/security-audit --config=p/owasp-top-ten .
# For JavaScript/TypeScript specifically
semgrep --config=p/javascript --config=p/typescript .
# Language-specific
semgrep --config=p/python # Python — bandit-equivalent rules
semgrep --config=p/php # PHP including WordPress patterns# gitleaks — across history too
brew install gitleaks
gitleaks detect --source . --report-format json --report-path /tmp/gitleaks.json
gitleaks detect --source . --log-opts="--all" # scan all branches + history
# trufflehog — different ruleset, often catches things gitleaks misses
trufflehog git file://. --json --only-verified > /tmp/trufflehog.json# npm
npm audit --omit=dev --audit-level=high
# Better — Socket for behavior-level signals
# (https://socket.dev — runs in CI on PRs)
# OSV-Scanner — broader than npm audit
osv-scanner --recursive .
# pip-audit for Python
pip-audit --strict -r requirements.txt# Trivy — image scanning, IaC scanning, secret scanning
trivy fs --severity HIGH,CRITICAL .
trivy image myapp:latest --severity HIGH,CRITICAL
trivy config . # Dockerfile + k8s + terraform misconfigsEnable in repo Settings → Code security → CodeQL analysis. It's free for public repos and worth its quotas for private. The results land in the Security tab; treat them as candidates, not verdicts.
| Tool | Catches | Misses |
|---|---|---|
| Semgrep | Pattern-shaped vulns (SQL string-concat, unsafe deserialization, missing CSRF) | Logic bugs, broken access control, business-logic issues |
| Gitleaks | Token-shape secrets in code/history | Custom secret formats, encrypted-at-rest values |
| npm audit | Known CVEs against pinned versions | Malicious-by-design packages, unreported issues |
| Socket | Behavior changes (sudden network calls, install scripts) | Pre-existing issues in established packages |
| Trivy | Image CVEs, misconfigured IaC, secrets in images | Application logic, runtime behavior |
| CodeQL | Dataflow-level vulns (taint analysis) | Issues outside its rule set, recent CVEs not yet ruled |
No tool finds broken access control. That is the single most common high-severity finding in real audits, and it requires manual review. Plan time accordingly.
Auth surface is where the highest-impact findings cluster. Walk every entry point and answer:
GET /invoices/:id must verify the invoice belongs to the requesting user.HttpOnly, Secure, SameSite=Lax?# Find every route + look for the auth check
grep -rEn "app\.(get|post|put|delete|patch)\(['\"]" src | head -40
# Then for each, check the handler for: session lookup, role check, owner checkSee auth-hardening for the deep dive and the checklist.
Every place untrusted input enters the system:
# SQL — anything that concatenates user input
grep -rEn "(\\.query\\(|\\.execute\\(|raw\\().*\\+.*req\\." --include='*.{js,ts,py}' . | head
grep -rEn 'f"SELECT.*\\{|f"INSERT.*\\{' --include='*.py' .
# HTML rendering — anything that dangerouslySetInnerHTML, v-html, .innerHTML
grep -rEn 'dangerouslySetInnerHTML|v-html|\\.innerHTML\\s*=' --include='*.{tsx,jsx,vue,ts,js}' .
# Shell execution
grep -rEn 'child_process|execSync|spawn|popen|os\\.system|subprocess\\.(run|call|Popen)' --include='*.{js,ts,py}' . | head
# Eval and friends
grep -rEn '\\beval\\(|new Function\\(|exec\\(' --include='*.{js,ts,py}' . | head
# File path joining with user input
grep -rEn 'path\\.join.*req\\.|os\\.path\\.join.*request' --include='*.{js,ts,py}' . | headEvery hit is a candidate. Read the surrounding code. Most are fine; some are critical.
A quick checklist with concrete searches for each Top-10 category (Web Apps, 2021 edition):
A01 — Broken Access Control (most common, hardest to grep)
grep -rEn ":id|:slug" src/routes — every parameterized route is a candidateA02 — Cryptographic Failures
grep -rEn 'md5|sha1|DES|crypto\.createCipher\b' --include='*.{js,ts,py}' . # deprecated/weak
grep -rEn 'http://' --include='*.{js,ts,py,html}' . | grep -v 'w3.org\|example\.com\|localhost'A03 — Injection
grep -rEn 'LDAP|ldap_search' . if LDAP is in scopegrep -rEn '\$where|\$regex' --include='*.{js,ts}' .A04 — Insecure Design — by inspection, not grep
A05 — Security Misconfiguration
grep -rEn 'NODE_ENV.*development|DEBUG\s*=\s*True|app\.debug\s*=\s*True' --include='*.{js,ts,py}' .
grep -rE 'cors.*\*|Access-Control-Allow-Origin.*\*' --include='*.{js,ts,py}' .A06 — Vulnerable and Outdated Components — npm audit, osv-scanner (Step 3)
A07 — Identification and Authentication Failures — auth surface walkthrough (Step 4)
A08 — Software and Data Integrity Failures
grep -rE 'pickle\\.loads|yaml\\.load(\\(|\\s)' .A09 — Security Logging and Monitoring Failures
log-strategy.A10 — Server-Side Request Forgery (SSRF)
grep -rEn 'fetch\\(.*req\\.|axios.*req\\.|requests\\.(get|post)\\(.*request' --include='*.{js,ts,py}' . | headSee dependency-supply-chain for the deep workflow. Specifically for audit:
npm audit --audit-level=high been run recently? What does it say?.env on disk?See vps-hardening, docker-container-security, github-actions-security, cloudflare-hardening, backend-architecture.
The report exists to drive action. Optimize for "can a different engineer fix this in a sprint?"
## [CRITICAL] Broken access control on /api/invoices/:id
### Summary
Any authenticated user can read any invoice by ID. No owner check.
### Evidence
- File: src/api/invoices/[id]/route.ts:12
- Reproduction: as user A, fetch /api/invoices/<an id belonging to user B>
$ curl -H "Cookie: $A_SESSION" https://app.example.com/api/invoices/$B_INVOICE_ID
→ 200 OK with B's data
### Impact
Cross-tenant data exposure. Any logged-in user reads every invoice.
### Remediation
Add owner check in the handler:
const invoice = await db.invoices.findFirst({ where: { id, userId: session.userId }});
if (!invoice) return NextResponse.json({ error: 'not found' }, { status: 404 });
### Severity reasoning
CRITICAL — affects all customer data, exploitable by any logged-in user, no
detection in current monitoring.
### Suggested owner: <name>
### Suggested deadline: <date — typically 7 days for critical>Use a small scale, consistently applied:
Aggressive severity inflation kills the report's usefulness. If everything is HIGH, nothing is HIGH.
A reader skims for CRITICALs and HIGHs first. Make that easy. Within severity, group by area (auth, data handling, infra) so an owner can take their slice.
Decision-makers read the summary, not the report. Cover:
npm audit output without synthesis or prioritization. Tool output is candidates, not findings.Stop. Notify the client / stakeholder same-day if the finding affects customer data, money, or trust. Holding a CRITICAL for a final report on Friday when you found it on Monday is itself a finding.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.