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
| Source | What it can show | Limits |
|---|---|---|
| Built artifacts and images | The actual files and versions shipped | Only for builds you still have |
| CI logs | Install output listing resolved versions | Retention varies, and logs may be quiet |
| Runner or build caches | Package files cached by past installs | Can be wiped or overwritten |
| Registry proxy or mirror logs | Which versions were requested and served, and when | Only if you run one and kept logs |
| Developer machines | Local installs and lock files not committed | Slow 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
- Get the window. From the advisory, note when the bad version was published and, if stated, when it was removed.
- List builds in the window. Use CI history to list every build that ran an install.
- Inspect outputs. For images, run a listing of installed packages from the image itself. For bundles, unpack and read package metadata.
- Read logs. Search install logs for the package name. Note builds with no data.
- Decide per build. Mark each as confirmed bad, confirmed clean, or unknown.
- 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.