Locking and updating dependencies

Two obligations pulling in opposite directions

Requirement What it demands What it pushes you to do
Annex I, Part I — no known exploitable vulnerability at placing on the market Components must be current Update often
Annex I, Part II, point 2 — remediate without delay The same, continuously Update fast
Art. 13(8) — five-to-ten-year support period Be able to rebuild identically a version shipped eight years ago Freeze everything

The Regulation therefore demands freshness and reproducibility at the same time. The answer is not a soft compromise: it is to freeze precisely, and update deliberately.

Freezing: the lock file

A manifest declares ranges (“version 5 or above”); a lock file records the exact resolution, transitive dependencies included, with hashes.

Without one, two builds of the same code on two dates produce two different artefacts. The consequences are directly regulatory:

  • the SBOM no longer reliably describes what was shipped;
  • rebuilding an old version becomes impossible, and so does the support period;
  • a silent substitution of a dependency goes unseen.

The rule: the lock file is committed, it is part of the source, and a publishable build fails if resolution departs from it. That is what the strict install modes of the various ecosystems guarantee, by refusing to update the lock file on the fly.

Freeze what is not an application dependency too

This is the most common blind spot: libraries get locked, and everything else in the chain is left mutable.

Element Mutable reference — to avoid Immutable reference
Reused CI action or step Version tag Full commit hash
Container base image :latest, or a version tag Content digest
Remote script run by the chain URL pointing at the main branch Frozen URL + hash verification
Tool installed on the fly “latest version” Exact version, hash verified

Why this is decisive. A tag can be repointed to another commit without any of your references changing. That is exactly the attack that exposed the secrets of thousands of chains in March 2025 — see Reference incidents. A hash cannot be repointed.

Updating: deliberately, not automatically

Freezing without updating produces the opposite of the intended result: a product that is reproducible and vulnerable.

Update bots — Dependabot, Renovate — are the standard tooling. They open pull requests when a version is published, with release notes and, depending on configuration, the vulnerability fixed.

But an update bot is itself a vector. An automatically merged version bump introduces third-party code straight into production. Three safeguards:

Safeguard Effect
Quarantine delay No version published less than N days ago is proposed. Malicious packages are usually pulled within hours or days
Restricted auto-merge Limited to security fixes on allow-listed components, and never for a major version change
Human review of sensitive dependencies An explicit list of components whose every bump goes through a person

Controlled ingestion: cache or decision point?

Routing dependencies through an internal mirror is widespread good practice, but two arrangements are often conflated:

Cache or mirror Decision point at ingestion
Function Serves faster, survives upstream outages Allows, denies, quarantines
Timing After download Before entry into the organisation
Faced with a malicious package It propagates it, and keeps it It blocks it

A cache accelerates; it does not govern. If the goal is to stop a typosquatted or freshly published package from entering, the decision must be applied before ingestion, with a policy that lives beside the code rather than in a console.

Often overlooked: configuration alone is not enough. As long as a workstation can reach the public registry directly, bypassing is trivial. Egress filtering is what makes the rule effective.

Reproducibility, a long-term requirement

On a product covered by a ten-year support period, you must be able to rebuild in eight years. That means retaining, alongside the code:

  • the lock file of the shipped version;
  • the hashes of base images and build tools;
  • a copy of upstream artefacts — a public registry is not an archival service, and packages do disappear;
  • the chain definition as it stood.

The reproducible builds effort takes the logic to its conclusion: two builds of the same code produce bit-for-bit identical artefacts. It is demanding, and it is the only proof a third party can genuinely verify.

The overlap is worth stating: what the Regulation requires you to retain for the support period, and what the GPL requires you to supply as “corresponding source”, are the same set of artefacts. See Desktop or command-line application.

Checklist

  • Committed lock file for each ecosystem
  • Publishable build in strict mode, failing if resolution departs from the lock file
  • CI actions and steps pinned by commit hash
  • Base images pinned by content digest
  • Update bot active, with a quarantine delay
  • Auto-merge limited to security fixes on allow-listed components
  • List of dependencies requiring mandatory human review
  • Dependencies served by an internal mirror, with egress filtering
  • Upstream artefacts archived for the duration of the support period
  • Annual test: rebuild a version shipped more than two years ago