Tech With Htunn
  • Blog Content
  • 🤖Artificial Intelligence
    • 🧠Building an Intelligent Agent with Local LLMs and Azure OpenAI
    • 📊Revolutionizing IoT Monitoring: My Personal Journey with LLM-Powered Observability
  • 📘Core Concepts
    • 🔄Understanding DevSecOps
    • ⬅️Shifting Left in DevSecOps
    • 📦Understanding Containerization
    • ⚙️What is Site Reliability Engineering?
    • ⏱️Understanding Toil in SRE
    • 🔐What is Identity and Access Management?
    • 📊Microsoft Graph API: An Overview
    • 🔄Understanding Identity Brokers
  • 🔎Security Testing
    • 🔍SAST vs DAST: Understanding the Differences
    • 🧩Software Composition Analysis (SCA)
    • 📋Software Bill of Materials (SBOM)
    • 🧪Dependency Scanning in DevSecOps
    • 🐳Container Scanning in DevSecOps
  • 🔄CI/CD Pipeline
    • 🔁My Journey with Continuous Integration in DevOps
    • 🚀My Journey with Continuous Delivery and Deployment in DevOps
  • 🧮Fundamentals
    • 💾What is Data Engineering?
    • 🔄Understanding DataOps
    • 👷The Role of a Cloud Architect
    • 🏛️Cloud Native Architecture
    • 💻Cloud Native Applications
  • 🏛️Architecture & Patterns
    • 🏅Medallion Architecture in Data Engineering
    • 🔄ETL vs ELT Pipeline: Understanding the Differences
  • 🔒Authentication & Authorization
    • 🔑OAuth 2.0 vs OIDC: Key Differences
    • 🔐Understanding PKCE in OAuth 2.0
    • 🔄Service Provider vs Identity Provider Initiated SAML Flows
  • 📋Provisioning Standards
    • 📊SCIM in Identity and Access Management
    • 📡Understanding SCIM Streaming
  • 🏗️Design Patterns
    • ⚡Event-Driven Architecture
    • 🔒Web Application Firewalls
  • 📊Reliability Metrics
    • 💰Error Budgets in SRE
    • 📏SLA vs SLO vs SLI: Understanding the Differences
    • ⏱️Mean Time to Recovery (MTTR)
Powered by GitBook
On this page
  • Why I Learned to Stop Worrying and Love SCA
  • The Day We Discovered What Was Hiding in Our Code
  • Building Our SCA Strategy with GitLab
  • Step 1: Setting Up Basic Dependency Scanning
  • Step 2: Creating Custom Policies for Different Project Types
  • Step 3: Adding License Compliance Checks
  • Step 4: Integrating with our Development Workflow
  • Real-World Challenges and How We Overcame Them
  • 1. False Positives
  • 2. Legacy Projects
  • 3. Developer Resistance
  • The Business Impact of Our SCA Implementation
  • Lessons Learned and Best Practices
  • Beyond Basic SCA: Where We're Heading Next
  • Final Thoughts: SCA as a Foundation for DevSecOps
  1. Security Testing

Software Composition Analysis (SCA)

When I joined my previous fintech startup company as a DevSecOps engineer four years ago, we had a severe security incident that I'll never forget. An outdated version of a popular npm package in our e-commerce platform contained a vulnerability that allowed attackers to inject malicious code.

That painful experience taught me the critical importance of Software Composition Analysis (SCA). Today, I want to share my journey implementing SCA into our DevSecOps pipeline using GitLab, and how it transformed our approach to managing third-party dependencies.

Why I Learned to Stop Worrying and Love SCA

Before our security incident, like many developers, I'd casually add packages to projects with little thought beyond "does it solve my problem?" A quick npm install or pip install and I was off to the races. I didn't realize I was potentially introducing ticking time bombs into our codebase.

Software Composition Analysis (SCA), as I've come to appreciate, is essentially an X-ray machine for your codebase. It reveals all the open-source components and third-party libraries hiding in your applications, along with any vulnerabilities or license issues they might harbor.

The Day We Discovered What Was Hiding in Our Code

After our security incident, our first comprehensive SCA scan was eye-opening. I remember staring at the results in disbelief:

  • 43% of our dependencies were outdated by at least two major versions

  • 12 components had known critical vulnerabilities

  • 8 libraries violated our company's licensing policies

  • 3 packages were effectively abandoned by their maintainers

Even more shocking was finding components we didn't even know we were using! These were transitive dependencies—packages that our direct dependencies relied on.

Building Our SCA Strategy with GitLab

After evaluating several tools, I decided to implement SCA using GitLab's built-in Dependency Scanning capabilities. Here's the approach I developed and have refined over the past four years:

Step 1: Setting Up Basic Dependency Scanning

I started by adding dependency scanning to our .gitlab-ci.yml file:

include:
  - template: Security/Dependency-Scanning.gitlab-ci.yml

variables:
  # Use custom Docker image for Node.js projects
  DS_NODEJS_SCAN_IMAGE_SUFFIX: '-custom'
  # Enable scanning for all supported package managers we use
  DS_PYTHON_VERSION: 3
  DS_JAVA_VERSION: 11

# We can customize dependency scanning job
dependency_scanning:
  variables:
    # Only alert on high and critical vulnerabilities at first
    DS_SEVERITY_THRESHOLD: "high"
  artifacts:
    paths:
      - gl-dependency-scanning-report.json
    expire_in: 1 week

This basic setup immediately started catching issues, but I soon realized we needed more nuanced control.

Step 2: Creating Custom Policies for Different Project Types

Different projects have different risk profiles. Our public-facing e-commerce platform needed stricter controls than our internal admin tools. I implemented custom policies using GitLab's scanning profiles:

# Custom policy definition
dependency_scanning:
  variables:
    DS_DEFAULT_ANALYZERS: "gemnasium-maven,gemnasium-python,gemnasium-nodejs"
    DS_EXCLUDED_PATHS: "tests/, docs/, examples/"
  rules:
    # High security requirements for payment-related services
    - if: $CI_PROJECT_PATH =~ /payment-services/
      variables:
        DS_SEVERITY_THRESHOLD: "low"
        DS_REMEDIATE: "true"
    # Standard requirements for other projects
    - if: $CI_COMMIT_BRANCH
      variables:
        DS_SEVERITY_THRESHOLD: "medium"

Step 3: Adding License Compliance Checks

Security vulnerabilities weren't our only concern. After our legal team raised concerns about open-source license compliance, I added license scanning:

include:
  - template: Security/Dependency-Scanning.gitlab-ci.yml
  - template: Security/License-Scanning.gitlab-ci.yml

license_scanning:
  variables:
    LICENSE_FINDER_CLI_OPTS: '--decisions-file=.license_decisions.yml'
  artifacts:
    reports:
      license_scanning: gl-license-scanning-report.json

I created a .license_decisions.yml file to whitelist approved licenses and explicitly approve/deny certain dependencies:

---
- - :approve
  - lodash
  - :who: "Jane Doe"
    :why: "Reviewed by legal team and approved"
    :when: 2024-05-15
- - :deny
  - crypto-js
  - :who: "John Smith"
    :why: "License incompatible with our product"
    :when: 2024-06-01

Step 4: Integrating with our Development Workflow

The final piece was making SCA results actionable within our workflow. I configured GitLab to:

  1. Show vulnerabilities directly in merge requests

  2. Block merges for critical issues

  3. Create automatic issues for remediation

dependency_scanning:
  artifacts:
    reports:
      dependency_scanning: gl-dependency-scanning-report.json
  after_script:
    - |
      if [ -f "gl-dependency-scanning-report.json" ]; then
        echo "Creating tickets for critical vulnerabilities..."
        python3 ./scripts/create_vulnerability_tickets.py gl-dependency-scanning-report.json
      fi

My custom Python script parsed the JSON report and created GitLab issues assigned to the appropriate teams.

Real-World Challenges and How We Overcame Them

Implementing SCA wasn't without challenges. Here's how we addressed the major ones:

1. False Positives

Early on, we were flooded with false positives—vulnerabilities that didn't apply to our usage context.

Solution: I created a vulnerability exception process. Team members could request exceptions with proper justification, which I'd review and add to our configuration:

variables:
  DS_EXCLUDED_VULNERABILITIES: "CVE-2020-1234, CVE-2020-5678"

2. Legacy Projects

Our older projects had mountains of outdated dependencies that couldn't be updated overnight.

Solution: We implemented a phased approach, focusing first on critical vulnerabilities, then high, and so on. For each project, we created a dependency roadmap with realistic timelines.

3. Developer Resistance

Initially, some developers saw SCA as "yet another hurdle" slowing down development.

Solution: I created dashboards showing vulnerabilities caught and organized "vulnerability of the week" sessions where I'd explain recent findings in practical terms. Once developers saw how SCA prevented issues that would have caused production incidents, resistance faded.

The Business Impact of Our SCA Implementation

After fully implementing our SCA strategy, we saw dramatic improvements:

  1. 83% reduction in vulnerable dependencies across our codebase

  2. Zero security incidents related to third-party code in the past two years

  3. 40% faster dependency updates due to clear visibility and prioritization

  4. Successful SOC 2 compliance with minimal additional effort due to our comprehensive SBOM

  5. Improved developer awareness about security and licensing risks

Lessons Learned and Best Practices

After four years of working with SCA tools, here are my top recommendations:

  1. Start with high-risk projects: Focus your initial efforts on public-facing and critical applications

  2. Integrate early in the development lifecycle: Catching issues in IDE or during commits is better than in CI

  3. Create clear remediation paths: Don't just report issues—provide guidance on fixing them

  4. Balance security with productivity: Tune your policies to avoid alert fatigue

  5. Build a dependency governance process: Establish procedures for adding new dependencies

One practice that's been particularly effective is our "dependency Tuesday" — we dedicate time each week to update dependencies and address SCA findings.

Beyond Basic SCA: Where We're Heading Next

Our SCA journey continues to evolve. Here's what I'm working on implementing next:

  1. Container scanning integration to analyze base images and installed packages

  2. Runtime SCA to detect vulnerabilities in running applications

  3. Automated remediation using GitLab's auto-fix capabilities

  4. Supply chain integrity verification to ensure dependencies haven't been tampered with

Final Thoughts: SCA as a Foundation for DevSecOps

Looking back, implementing SCA was one of the most impactful security initiatives in our organization. Beyond just finding vulnerabilities, it built a culture of dependency awareness and responsibility.

If you're considering implementing SCA in your organization, I encourage you to start small, focus on critical applications, and integrate with your existing workflows using GitLab's tools. The peace of mind from knowing what's in your software—and that it's secure—is well worth the effort.

Remember, in today's world where applications are more assembled than written from scratch, SCA isn't just a security tool—it's an essential part of responsible software development.

PreviousSAST vs DAST: Understanding the DifferencesNextSoftware Bill of Materials (SBOM)

Last updated 2 days ago

🔎
🧩