Read the RECORD file inside the package's dist-info directory. It lists each installed file with a hash and size. Recompute the hashes on disk and compare. A mismatch means a file changed after install. It cannot tell you the original was trustworthy, because the installer wrote RECORD from the same package.
What RECORD is
The Python packaging specification for recording installed packages says each installed project must add a dist-info directory next to its modules, usually in site-packages. It contains a RECORD file: a CSV with one line per installed file, giving the path, a hash and a size.
The hash is the algorithm name, an equals sign, and the digest encoded in URL safe base64 without padding. The spec says hash and size may be left empty. Compiled bytecode entries and the RECORD file itself commonly have empty values. For other files, leaving them out is discouraged because it prevents verifying the integrity of the installed project.
The spec also says that if RECORD is present it must list all installed files, except bytecode for listed source files. That completeness is what makes it useful as an inventory.
A small checker
This script uses the standard library only. It reads RECORD through importlib.metadata and reports files that are missing or changed.
import base64, hashlib, sys
from importlib.metadata import distribution
def check(name):
changed, no_hash = [], 0
for f in distribution(name).files or []:
if f.hash is None:
no_hash += 1
continue
try:
data = f.locate().read_bytes()
except OSError:
changed.append((str(f), "missing"))
continue
digest = hashlib.new(f.hash.mode, data).digest()
want = base64.urlsafe_b64encode(digest).rstrip(b"=").decode()
if want != f.hash.value:
changed.append((str(f), "changed"))
return changed, no_hash
changed, no_hash = check(sys.argv[1])
for path, why in changed:
print(why, path)
print("entries without a hash:", no_hash)
Run it with the isolated flag so a stray file in the current folder cannot shadow a module, passing the package name as the argument.
Expect some noise
When I ran a script like this against a Python that ships with an operating system, it reported a few differences, such as empty package files that had been rewritten and command scripts recorded at paths outside the environment. Distributors patch and relocate files. So treat output as a list to triage, not a verdict. Start with a clean virtual environment you built yourself, where differences are meaningful.
What a match tells you
| Result | Meaning |
|---|---|
| All hashes match | Files are as the installer recorded them |
| Changed file | Edited after install, by a person, a tool or an attacker |
| Missing file | Deleted or moved |
| Extra file not in RECORD | Not covered by this check, look for it separately |
The last row is the important blind spot. RECORD does not list files that were added later. Planted files, such as a startup hook or an extra module, will not show up as a mismatch. Compare the actual directory listing with RECORD too. See Python pth files and startup code.
What it cannot prove
RECORD is written at install time. If you installed a malicious package, RECORD faithfully describes the malicious files. To tie an install back to a known good artifact, use hash-checking mode at install, which compares the downloaded file with a hash you recorded. See how pip hash checking works.
Where this helps
Incident response is the best use. If you suspect a host, compare RECORD against disk for your critical packages, and list files that RECORD does not know about. It is a quick local check that needs no network.
Safeguard's dependency scanning and SBOM generation give you the inventory side, so you can see which packages and versions to check. A free scan is available at gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen. Notice how an inventory of packages is the starting point for any per package check.
Quick check
Does pip verify RECORD every time Python starts?
Not as far as the specification goes. It describes RECORD as the list of installed files, which tools use for jobs such as uninstalling. Verification is something you run yourself.
Will RECORD reveal a file an attacker added?
Not by itself. Added files are not listed, so compare the directory contents too.
Sources
Last reviewed: 19 October 2026.