Security scanning in CI feels like a good idea right up until you switch it on and get 400 alerts on your first run. Then it gets ignored. Then someone finds a vulnerability in production that one of those 400 alerts would have caught, and the post-mortem is uncomfortable.
The problem isn’t usually the tooling — it’s the configuration and the way it’s introduced. Start with the wrong ruleset or the wrong scope and you’ve created noise that the team will work around rather than work with. Here’s how to add useful security scanning to a developer workflow without making everyone miserable.
The three layers worth having
SCA (Software Composition Analysis) scans your dependencies for known vulnerabilities. If you’re pulling in an npm package with a disclosed CVE, SCA catches it. This is the most immediately useful layer because the vulnerabilities are confirmed, the fix is usually “upgrade the package,” and the signal-to-noise ratio is high compared to static analysis.
SAST (Static Application Security Testing) analyses your source code for security bugs — SQL injection patterns, hardcoded secrets, unsafe deserialisation, and similar issues. Quality varies significantly by tool and by language. SAST is worth having but generates more noise than SCA and needs careful tuning to the codebase.
Container and IaC scanning checks your Docker images for vulnerable base layers and your Terraform or Kubernetes configs for misconfigurations. If you’re shipping containers — and most teams are — this layer is important because a vulnerable base image can silently expose everything running on it.
Snyk: the developer-first dependency scanner
Snyk is the standard choice for dependency vulnerability scanning in most modern development environments. It integrates with GitHub, GitLab, Azure DevOps, and Bitbucket as a PR check. When you open a pull request that changes a dependency, Snyk tells you whether the version you’re moving to has known issues. When a new CVE drops affecting something in your dependency tree, Snyk can automatically file a PR to upgrade the affected package.
The free tier is genuinely useful for open-source projects and small teams — it covers the basics and integrates with GitHub without anything to pay. For container scanning, Snyk scans Docker image layers and flags base images with known vulnerabilities, with suggestions for a less-vulnerable alternative base.
What Snyk does better than a raw CVE list is prioritisation. Not all vulnerabilities are equal. A CVE in a dev-only dependency that requires authentication to exploit in production is lower priority than an unauthenticated RCE in a runtime dependency. Snyk surfaces this context — reachability analysis, severity given your actual exposure — rather than presenting a flat list of CVE numbers and letting you figure out what matters.
Semgrep: SAST you can actually reason about
Semgrep is a static analysis tool with an enormous open-source rule library and a model where rules are human-readable patterns rather than opaque ML classifications. That distinction matters. When Semgrep flags something, you can read the rule that caught it, understand what it’s looking for, and judge whether it applies to your specific codebase. That transparency makes it much easier to tune out false positives and trust the remaining alerts.
The Community edition is free and includes thousands of rules across languages and frameworks. The key to not hating SAST is starting with a small, high-confidence ruleset — the OWASP Top 10 rules for your primary language plus any framework-specific security rules — and only expanding from there once you trust the baseline signal.
Semgrep runs locally in under a second on most codebases, which means developers can run it before pushing rather than only finding out about issues in CI. For pull request integration, configuring Semgrep to only flag issues on the lines changed in the PR (rather than the whole codebase) keeps noise manageable during initial rollout. You address the legacy issues separately, on your own schedule.
Trivy: one tool for containers and IaC
For container and infrastructure scanning, Trivy from Aqua Security covers OS packages, language dependencies, embedded secrets, and IaC misconfiguration — all in a single CLI. It’s free and fast.
# Scan a container image
trivy image your-registry/your-app:latest
# Scan the local filesystem for vulnerable packages and leaked secrets
trivy fs .
# Scan Terraform config for misconfigurations
trivy config ./terraform
Adding Trivy as a GitHub Action to fail builds on CRITICAL or HIGH vulnerabilities in production images is a good starting point. The --ignore-unfixed flag avoids alerting on vulnerabilities that have no available fix — there’s nothing productive to do about those until a fix exists, so they shouldn’t block deploys.
A minimal GitHub Actions security pipeline
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
ignore-unfixed: true
severity: 'CRITICAL,HIGH'
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: p/owasp-top-ten
This combination takes a couple of minutes to run and catches the most common and most critical issues without generating pages of output that nobody will read.
The friction argument
Adding security gates to CI does create friction. A PR that fails a security check takes longer to merge. That friction is often justified — a vulnerability caught pre-merge is much cheaper to fix than one caught post-deploy or in a penetration test. But it only works if the signal-to-noise ratio is high enough that developers trust the alerts. One week of working around irrelevant false positives is enough to get security scanning disabled and never re-enabled.
Start narrow. High-confidence rules only. Prove that the alerts are worth the interruption before expanding. The tooling is mature enough now that a well-configured security pipeline is achievable in an afternoon; an over-configured one creates resentment that outlasts the setup.
The alternative — discovering what these tools would have caught during a client security assessment or after a breach notification — is a significantly less comfortable conversation.