# Loom Security Scan

> Quick routine security checks for secrets, dependencies, container images, and common vulnerabilities.

- Skill: `cosmix/loom-security-scan` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cosmix/loom-security-scan`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cosmix/loom-security-scan/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: cosmix (https://skillmd.com/u/cosmix)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cosmix/loom-security-scan

---


# Security Scan

Fast, automatable checks to run pre-commit / in CI — catch secrets, known-CVE deps, image and IaC misconfig early. This is the *tooling* skill; for methodology and compliance use `loom-security-audit`, for STRIDE use `loom-threat-model`, for deep dependency/SBOM work use `loom-dependency-scan`.

## Tool Selection Matrix

| Scan type | Tool | Alternative | Notes |
| --------- | ---- | ----------- | ----- |
| Secrets | TruffleHog | Gitleaks | TruffleHog *verifies* live creds; Gitleaks is regex-fast |
| Deps (JS) | npm audit | osv-scanner, Snyk | `--audit-level=high` |
| Deps (Python) | pip-audit | safety | pip-audit uses OSV/PyPI advisory DB |
| Deps (Go) | govulncheck | osv-scanner | call-graph aware → fewer false positives |
| Deps (Rust) | cargo audit | cargo-deny | RustSec DB |
| Container image | Trivy | Grype | `--scanners vuln,secret,config` |
| SAST multi-lang | Semgrep | CodeQL | `p/security-audit`, `p/secrets` |
| SAST Python | Bandit | Semgrep | — |
| SAST Go | gosec | Semgrep | — |
| Dockerfile | hadolint | Trivy config | best-practice lint |
| IaC (Terraform) | tfsec / trivy config | Checkov | — |
| IaC (K8s) | kubesec / trivy | Checkov | — |
| Universal (fs+img, vuln+secret+config) | Trivy | osv-scanner | one binary for most CI needs |

## Priority Order

Run cheapest/highest-signal first; a secret in git history is worse than a medium CVE.

### 1. Secrets (Critical)

Prefer dedicated tools over grep — they cut false positives and TruffleHog verifies whether a key is *live*.

```bash
trufflehog filesystem . --only-verified --no-update   # only credentials confirmed active
gitleaks detect --source . --redact                   # scans full git HISTORY by default
```

⚠ Secret-scanning gotchas:

- **Scan history, not just the worktree.** A rotated key still lives in old commits and forks. `gitleaks detect` walks history; `gitleaks detect --no-git` / `trufflehog filesystem` only see current files. A committed-then-deleted secret must be **rotated**, not just removed — deletion doesn't scrub history.
- `--only-verified` (TruffleHog) suppresses unverifiable/expired hits — great for CI signal, but it will miss a secret whose endpoint it can't reach; run a full pass periodically.
- Regex fallback for a quick look (dedicated tools are better): AWS keys `(AKIA|ASIA)[A-Z0-9]{16}`, PEM `-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----`, generic `(password|secret|token|api[_-]?key)\s*[:=]\s*['"][^'"]{8,}`.

⚠ Secrets leak at **runtime**, beyond git — scanners won't catch these; flag them in review:

- **Process argv** — a secret passed as a CLI arg (`mytool --token=abc`) is world-visible in `ps`/`/proc/*/cmdline`. Pass via env or stdin/file instead.
- **Env inheritance** — child processes inherit the parent's env; a spawned subprocess or crash-reporter can exfiltrate `AWS_SECRET_ACCESS_KEY`. Scope/scrub env before spawning untrusted code.
- **Logs & error/stack traces** — request bodies, `Authorization` headers, DB URLs with passwords, and exception dumps routinely leak secrets. Redact structured fields; never log full request objects.
- **Client-side & URLs** — secrets in query strings land in access logs, referers, and browser history; `.env`/`NEXT_PUBLIC_*` bundled into frontend builds ship to users.

### 2. Dependency CVEs (High)

```bash
npm audit --audit-level=high        # JS   (yarn audit --level high)
pip-audit                           # Python
govulncheck ./...                   # Go   (reachability-aware)
cargo audit                         # Rust
osv-scanner -r .                    # multi-ecosystem, lockfile-driven
```

For triage, SBOM, license, and supply-chain (typosquat/dependency-confusion) → `loom-dependency-scan`. ⚠ `npm audit` reports advisories against the *lockfile* including transitive/dev-only deps — a "critical" in a build-time devDependency may be unreachable at runtime; confirm reachability before blocking a release.

### 3. Container Images (High)

```bash
trivy image --severity HIGH,CRITICAL --scanners vuln,secret,config myimage:tag
hadolint Dockerfile
trivy config --severity HIGH,CRITICAL Dockerfile   # pre-build misconfig lint
```

⚠ Scan the exact **immutable digest** (`myimage@sha256:…`) you'll deploy, not a floating `:latest` (mutable → scan/deploy drift). Rebuild on base-image CVEs; a passing scan goes stale as new CVEs land.

### 4. SAST (Medium)

```bash
semgrep --config=p/security-audit --config=p/secrets .   # fast, low-FP defaults
bandit -r . -ll                                          # Python, high-severity only
gosec -severity high ./...                               # Go
```

### 5. IaC / Config (Medium)

```bash
tfsec . --minimum-severity HIGH
kubesec scan deployment.yaml
checkov -d . --compact
```

## CI Integration

Set nonzero exit → fail the job. ⚠ `npm audit ... || true` never fails CI (swallows exit code) — only use `|| true` for advisory-only steps you deliberately don't gate on.

```yaml
# GitHub Actions
jobs:
  security:
    permissions: { contents: read }
    runs-on: ubuntu-latest
    steps:
      # Resolve and pin every action to a reviewed full commit SHA. Tags/branches,
      # including @main and @master, are mutable and are not production pins.
      - uses: actions/checkout@<full-commit-sha>
        with: { fetch-depth: 0 }          # full history for secret scan
      - uses: trufflesecurity/trufflehog@<full-commit-sha>
        with: { extra_args: --only-verified }
      # semgrep-action is archived. Use the maintained image pinned by digest;
      # `semgrep ci` is the Semgrep App platform mode, while this is CE mode.
      - name: Semgrep Community Edition
        run: >-
          docker run --rm -v "$GITHUB_WORKSPACE:/src" -w /src
          semgrep/semgrep@sha256:<reviewed-digest>
          semgrep scan --error --config=p/security-audit --config=p/secrets
      - uses: aquasecurity/trivy-action@<full-commit-sha>
        with: { scan-type: fs, severity: "HIGH,CRITICAL", exit-code: 1 }
```

```yaml
# Pre-commit (.pre-commit-config.yaml) — block secrets before they're committed
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks: [{ id: gitleaks }]
  - repo: https://github.com/returntocorp/semgrep
    rev: v1.52.0
    hooks: [{ id: semgrep, args: ["--config=p/secrets", "--error"] }]
```

## Interpreting Results

| Severity | Action | Timeline |
| -------- | ------ | -------- |
| Critical | Block merge, fix now | Hours |
| High | Fix before merge | Days |
| Medium | Plan a fix | Sprint |
| Low | Track | Backlog |

Common false positives — triage, don't blindly suppress: test fixtures / example creds (add to `.gitleaksignore` with a note), unreachable/dev-only dep CVEs (document acceptance), base64/UUIDs mistaken for secrets. Record accepted risks with a justification and reviewer so the next scan doesn't re-litigate them.

## Verification Checklist

- [ ] Secret scan covers **git history** (not just worktree); any historical hit → key rotated, not just deleted
- [ ] Dependency scan run for **every** ecosystem in the repo (a Python service with a JS build tool needs both)
- [ ] Container scan targets the deployed **digest**; Dockerfile linted (hadolint + trivy config)
- [ ] SAST run with a security ruleset (not just style)
- [ ] CI steps **fail** on Critical/High (no stray `|| true`); pre-commit blocks secrets locally
- [ ] CI grants minimal `GITHUB_TOKEN` permissions and pins every third-party action to a reviewed full commit SHA
- [ ] Findings triaged: confirmed / false-positive / accepted-risk, each with owner + justification
- [ ] Critical/complex/architecture findings escalated → `loom-security-audit`

## Escalate to `loom-security-audit`

Critical or novel findings, architecture-level concerns, compliance questions (SOC2/PCI/HIPAA/GDPR), or incident response — scanners find known patterns; humans/audits find logic and authorization flaws.

