FSD Frontend System Design

Part II β€” The Shield Β· Lesson 3.7

Dependency Security

In one lineYou wrote 5% of the code you ship β€” the other 95% is your attack surface too.

Where you've seen itThe event-stream incident. A maintainer handed the package to a stranger, who shipped wallet-stealing code that reached millions of installs through a transitive dependency.

  • Time15 min
  • DiagramDependency tree with one compromised node
  • Chapter3 Β· Security

Diagram

diagram
YOUR DEPENDENCY TREE β€” the risk is not at the top

  your-app
  β”œβ”€β”€ react                     you chose this
  β”œβ”€β”€ some-ui-kit               you chose this
  β”‚   β”œβ”€β”€ lodash                you didn't
  β”‚   β”œβ”€β”€ color-parser          you didn't
  β”‚   β”‚   └── tiny-helper  ☠    compromised β€” you've never heard of it
  β”‚   └── date-utils
  └── build-tool
      └── 340 more packages     ← postinstall scripts run as YOU

  Direct deps: ~20.  Actually installed: ~1,200.
diagram
FOUR WAYS A PACKAGE TURNS HOSTILE

  1. Maintainer account taken over    (weak password, no 2FA)
  2. Maintainer handover              (event-stream)
  3. Typosquatting                    reakt, lodahs, croos-env
  4. Dependency confusion             internal name published publicly,
                                      registry prefers the public one
diagram
WHERE THE CODE ACTUALLY RUNS

  npm install ──► postinstall script ──► your laptop, your CI,
                                         your secrets, your tokens
  build       ──► bundled ──────────────► every user's browser

  A malicious package doesn't need to be imported to run.

How it works

  1. Lockfile always committed. Without it, a fresh CI install can resolve a different, newer, compromised version.
  2. Audit in CI, not manually: npm audit --audit-level=high as a gate, plus Dependabot or Renovate for patches.
  3. Reduce the tree. Every dependency removed is a permanent risk reduction β€” do you need a package for isArray?
  4. Disable install scripts where possible (npm ci --ignore-scripts) and pin exact versions for anything sensitive.
  5. Prefix internal packages on a private scope so dependency confusion can't substitute a public one.

Trade-offs

PracticeCost
Pin exact versionsManual patch upgrades
--ignore-scriptsSome packages genuinely need them
Fewer dependenciesMore code you maintain
Fast patchingChurn, regression risk

Vet before adding: downloads and recency, open issue response time, number of maintainers, install-script presence, and whether the same job can be done in 20 lines of your own code.

Interview angle

"npm audit reports 40 vulnerabilities. What do you do?"

  • Triage by reachability first: a dev-only build tool's ReDoS is not a production incident.
  • Fix anything reaching production or with network/filesystem access; patch the rest on a schedule.
  • Then fix the process β€” audit gate in CI, automated patch PRs, and lockfile discipline.

Recap

  • Transitive dependencies are the real surface, and install scripts run before any code review.
  • Lockfile, CI audit gate, automated patches, fewer packages.
  • Vet on maintainer health, not just on GitHub stars.