Back to Blog
Lesson 23 of the CI/CD: Continuous Integration from Scratch course
DevOpsJuly 29, 20264 min read

Dependency Scanning: Automating Security in Your CI/CD Pipeline

Stop shipping vulnerable code. Learn how to automate dependency scanning in your CI/CD pipeline to catch known security flaws before they reach production.

securitydependenciesvulnerability scanningCI/CDgithub actions
Close-up of rusty industrial pipes and valves, showcasing aging machinery in a factory setting.

Previously in this course, we covered failing on lint errors, which ensures your code style remains consistent. In this lesson, we shift our focus from style to substance: automated security. Even if your code is perfect, your application is only as secure as the third-party libraries you rely on. Dependency scanning automates the process of checking your project's manifests against known vulnerability databases, acting as an early warning system for your supply chain.

The Problem: The Hidden Attack Surface

Modern applications are built like puzzles, with 80% or more of the codebase often coming from external dependencies. When a vulnerability is discovered in a package like lodash or requests, every application using that version becomes a target.

Manual checks are impossible to sustain. By the time you realize a dependency is compromised, you may have already deployed it to production. Dependency scanning tools automate this by analyzing your lockfiles (like package-lock.json or requirements.txt) and comparing them against public databases like the GitHub Advisory Database or the NVD (National Vulnerability Database).

Implementing Dependency Scanning in Your Pipeline

We will focus on two common tools: npm audit for Node.js projects and pip-audit for Python projects. Both are designed to be run in a non-interactive environment, making them perfect for CI.

Worked Example: Node.js with npm audit

npm audit comes pre-installed with Node.js. By default, it returns a non-zero exit code if it finds vulnerabilities, which is exactly what we want to "break the build" and stop a deployment.

Add this step to your existing GitHub Actions workflow job:

YAML
jobs:
  security-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Run security audit
        # The --audit-level flag allows you to set a threshold
        run: npm audit --audit-level=high

If npm finds any high or critical vulnerabilities, the step will fail, and your pipeline will stop. This forces developers to address the issue—either by updating the package or by explicitly acknowledging the risk—before the code can be merged.

Worked Example: Python with pip-audit

For Python, pip-audit is the industry standard. Unlike the basic pip list commands, it specifically queries the PyPI vulnerability database.

YAML
      - name: Install audit tool
        run: pip install pip-audit
      - name: Run security scan
        run: pip-audit

Hands-on Exercise

  1. Open your project's GitHub Actions YAML file.
  2. Add a new job titled security that runs before your testing job.
  3. Depending on your stack, include either npm audit or pip-audit.
  4. Commit and push your changes. If your dependencies are clean, the pipeline should pass.
  5. Bonus: Intentionally add a vulnerable version of a package to your manifest and verify that your pipeline fails as expected.

Common Pitfalls

  • Ignoring the "Low" severity noise: You might be tempted to run npm audit without flags. This often results in a flood of "Low" severity warnings that don't actually impact your application, leading to "alert fatigue." Start with --audit-level=high or critical to keep the signal-to-noise ratio manageable.
  • Forgetting the lockfile: Scanning only works if you have a lockfile (package-lock.json or poetry.lock). If you don't commit these, your CI will scan against floating versions, which is a major security risk, as discussed in our deep dive on dependency management.
  • Lack of periodic re-scanning: A pipeline only runs on push. If a new vulnerability is discovered for a package you already have, you won't know about it until your next code change. Consider setting up a scheduled workflow (e.g., once a week) that runs just the security scan.

FAQ

Q: What if I need to ignore a specific vulnerability? A: Both tools allow for "audit ignores." However, use these sparingly. Always document why you are ignoring a vulnerability in the code or a configuration file.

Q: Does this replace professional security audits? A: No. These tools only catch known vulnerabilities (CVEs). They cannot detect custom logic flaws, like the ones discussed in our guide to preventing dependency confusion, or architectural weaknesses.

Recap

Dependency scanning is your first line of defense in the software supply chain. By integrating npm audit or pip-audit into your CI pipeline, you ensure that known insecure code never enters your main branch. Remember: automated security is only effective if you act on the feedback it provides.

Up next: We will learn about Advanced Pipeline Caching to ensure our security scans and tests don't slow down our developer workflow.

Similar Posts