Safeguard
Supply Chain•

No lockfile: can you still tell which dependency version you installed?

With no lockfile and a compromised dependency, five evidence sources can show what was installed: artifacts, CI logs, images, caches and proxy logs.

Safeguard Security Team
4 min read

Often yes, but not from the repository. Without a lockfile, the manifest shows a range. To learn what was installed, inspect built artifacts and images, CI logs, runner caches and registry proxy logs, then compare timestamps with when the bad version was published. Expect gaps, and treat unknown as exposed.

Why the repository is not enough

A manifest such as package.json or requirements.txt often holds a range, not a version. A fresh install resolves whatever is newest within the range at that moment. Two builds a day apart can contain different versions of the same dependency. The npm documentation describes npm ci as needing an existing lockfile, which is the mechanism that makes installs repeatable. Without one, you have to reconstruct.

Five evidence sources

SourceWhat it can showLimits
Built artifacts and imagesThe actual files and versions shippedOnly for builds you still have
CI logsInstall output listing resolved versionsRetention varies, and logs may be quiet
Runner or build cachesPackage files cached by past installsCan be wiped or overwritten
Registry proxy or mirror logsWhich versions were requested and served, and whenOnly if you run one and kept logs
Developer machinesLocal installs and lock files not committedSlow to collect, easy to miss

For GitHub hosted repositories, the audit log can help with questions about who changed what on the organization side. GitHub's documentation says the organization audit log shows events from the last 180 days, and by default displays the past three months. It will not list installed package versions, but it can show repository and settings changes in your timeframe.

A reconstruction method

  1. Get the window. From the advisory, note when the bad version was published and, if stated, when it was removed.
  2. List builds in the window. Use CI history to list every build that ran an install.
  3. Inspect outputs. For images, run a listing of installed packages from the image itself. For bundles, unpack and read package metadata.
  4. Read logs. Search install logs for the package name. Note builds with no data.
  5. Decide per build. Mark each as confirmed bad, confirmed clean, or unknown.
  6. Treat unknown as exposed for credential decisions, and rebuild.

Fix the gap afterward

Add a lockfile and commit it, use a frozen install in CI, store an SBOM with each build, and keep install logs for a defined period. Run the one hour shadow dependency sweep to find other repositories with the same gap.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how scanning a built image lists what is inside it, which is the strongest evidence when the repository cannot answer.

Quick check

Is a manifest range enough to say we were not affected?

No. A range can resolve to a bad version. You need evidence from artifacts or logs.

What if we have no logs and no artifacts?

Treat the build as exposed, rotate credentials that were available to it, and rebuild from a pinned state.

Safeguard can help with the inventory side of this work. SBOM and dependency scanning show where a package and version appear across your projects, and policies and gates can stop a flagged version at the pull request. You can try a free scan at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.