A Dependency Vulnerability Put a Logistics SaaS's Users at Risk

TL;DR

An npm package a logistics SaaS had been using for two years had a critical prototype pollution vulnerability. The team didn't know until a security researcher contacted them. The vulnerable code was executing on every page load. Updating the dependency took 30 minutes; understanding why they hadn't caught this sooner took much longer.

Modern web apps are built on towers of dependencies. This particular logistics platform had 847 packages in its node_modules folder. One of them had been vulnerable for 8 months, and the team had no idea.

The Wake-Up Call

A security researcher emailed the company on a Tuesday morning. They'd been auditing applications using a popular utility library and found the logistics platform through Wappalyzer detection.

"Your application appears to be using lodash version 4.17.11, which has a known prototype pollution vulnerability (CVE-2019-10744). This could allow attackers to inject properties into JavaScript objects, potentially leading to remote code execution."

The lead engineer's first reaction was defensive. The team barely used lodash directly. But then a check of the package-lock.json revealed it was a dependency of a dependency. And yes, they were on a vulnerable version.

Understanding the Risk

Prototype pollution sounds academic until you realize what it means in practice:

  • Attackers can modify the behavior of built-in JavaScript objects
  • In Node.js, this can sometimes lead to remote code execution
  • In browsers, it can enable XSS attacks or authentication bypasses
  • The attack surface exists anywhere user input touches affected functions

The team ran npm audit for the first time in months. The results were sobering.

$ npm audit
found 23 vulnerabilities (7 low, 12 moderate, 4 high)
  run `npm audit fix` to fix them

Twenty-three vulnerabilities. Four of them high severity. And the team had been ignoring this for who knows how long.

  • Never ran npm audit in CI/CD pipeline
  • No automated dependency update process
  • Locked to specific versions without review
  • Assumed "if it works, don't touch it"
  • No security monitoring for third-party packages

The Fix

The immediate fix was simple:

npm audit fix

# For the stubborn ones that needed manual intervention
npm update lodash
npm update minimist
npm update node-fetch

But some packages had breaking changes. The team spent two days testing after updates, finding and fixing compatibility issues. It would have been much easier if they'd kept things updated incrementally.

Building Better Practices

After this incident, the team implemented proper dependency management:

# .github/workflows/security.yml
name: Security Audit
on:
  push:
  schedule:
    - cron: '0 0 * * 1'  # Weekly Monday scan

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm ci
      - run: npm audit --audit-level=moderate
      - uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

They also enabled Dependabot for automated pull requests when updates are available:

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
Key Lessons Learned
  • Run npm audit (or equivalent) in your CI/CD pipeline
  • Enable automated dependency updates (Dependabot, Renovate)
  • Review and update dependencies regularly, not just when things break
  • Use tools like Snyk or npm audit to catch vulnerabilities early
  • Understand your dependency tree - vulnerabilities hide in transitive dependencies
  • Don't ignore security warnings just because your app "works fine"

The Hidden Cost of Neglect

The technical fix took half a day. But the real cost was the risk the team had unknowingly exposed its users to for months. A prototype pollution attack could have allowed:

  • Session hijacking through manipulated objects
  • Privilege escalation if user roles were object-based
  • Data theft through modified API behavior
  • Complete server compromise in worst-case scenarios

The team was lucky. The researcher who found the vulnerability was ethical. Next time, they might not be so fortunate.

How often should I run npm audit?

Run it on every CI build to catch issues before deployment. Also run weekly scheduled audits to catch newly discovered vulnerabilities in existing dependencies.

What's the difference between npm audit and Snyk?

npm audit uses the npm advisory database and is free and built-in. Snyk has a larger vulnerability database, provides fix suggestions, and offers additional features like license compliance checking. Many teams use both.

Should I auto-merge Dependabot PRs?

For patch updates with passing tests, many teams auto-merge. For minor or major updates, manual review is safer. Always have good test coverage before enabling any auto-merge.

Scan your vibe coded projects for vulnerable dependencies and security issues.

Security Stories

A Dependency Vulnerability Put a Logistics SaaS's Users at Risk