# Package dependencies locked to specific versions

- **Pattern:** `ab-002412` (`security-hardening.dependency-security.lock-files`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002412
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002412)

## Why it matters

Without a committed lock file, dependency resolution is non-deterministic — `npm install` on different machines or at different times may pull different transitive dependency versions. CWE-1357 (Reliance on Insufficiently Trustworthy Component) and OWASP A06 (Vulnerable and Outdated Components) both flag unpinned dependencies. SLSA L2 and SSDF PW.4 require reproducible builds with verified dependency integrity. A supply-chain attack can introduce a malicious version of a widely-used package; without a lock file, your CI might silently install the compromised version the day it is published.

## Severity rationale

Low because unlocked dependencies primarily create supply-chain risk during installation rather than runtime, but they open a window for silent malicious version substitution on every install.

## Remediation

Commit the lock file and switch CI from `npm install` to `npm ci`:

```bash
# Verify the lock file is not gitignored
grep 'package-lock' .gitignore  # Should return nothing

# Commit the lock file
git add package-lock.json
git commit -m 'Add package-lock.json'
```

In your CI pipeline (`/.github/workflows/ci.yml`):

```yaml
- name: Install dependencies
  run: npm ci  # Installs exactly from lock file; fails if out of sync
```

`npm ci` is faster than `npm install` on CI because it skips the dependency resolution step.

## Detection

- **ID:** `lock-files`
- **Severity:** `low`
- **What to look for:** Count all package managers in use and verify each has a corresponding lock file. check that a lock file exists (`package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml`) and is committed to the repository. Verify that CI/CD uses the lock file (e.g., `npm ci` not `npm install`).
- **Pass criteria:** A lock file is committed to the repository. CI/CD installs using the lock file (`npm ci`, `yarn install --frozen-lockfile`, `pnpm install --frozen-lockfile`) — 100% of package managers must have lock files committed to version control. Report: "X package managers found, all Y have committed lock files."
- **Fail criteria:** No lock file committed. Lock file is listed in `.gitignore`. CI/CD runs `npm install` in a way that may update the lock file.
- **Skip (N/A) when:** Never — all projects with npm/yarn/pnpm dependencies should have a lock file.
- **Detail on fail:** `"package-lock.json not found in repository root — dependency versions not pinned"` or `"yarn.lock listed in .gitignore — lock file not committed to version control"`
- **Remediation:** Commit your lock file and use `npm ci` in CI/CD:

  ```bash
  # Ensure lock file is not in .gitignore
  grep "package-lock.json" .gitignore  # Should return nothing

  # In CI/CD pipeline, use npm ci instead of npm install
  npm ci  # Installs from lock file, fails if lock file is out of sync
  ```

  For new projects, `npm install` creates `package-lock.json`. Commit it:

  ```bash
  git add package-lock.json
  git commit -m "Add package-lock.json"
  ```

## External references

- cwe CWE-1357
- owasp A06
- slsa L2
- ssdf PW.4

Taxons: supply-chain

HTML version: https://auditbuffet.com/patterns/ab-002412
