Wheel archive and RECORD audit
Compare a local wheel filename, metadata, tags and every RECORD hash/size, distinguishing integrity failures, unsupported hashes and unverified signatures.
- 1Add input
- 2Adjust settings
- 3Get your result
Tool input and files are processed in this browser without being uploaded.
Before you start
Before installing an unfamiliar wheel, inspect whether its archive declarations agree with its bytes. This task reads the file without importing the package; a bad hash produces a failed audit, so generating a report never substitutes for passing verification.
How to use this tool
- Select a wheel with its original filename, or load the fixed small-file example.
- Review integrity status, verified files, failures, unsupported hashes and unverified signatures.
- Download the complete audit and check failures with a trusted producer; the report is not a security or installation approval.
Supported inputs and limits
Select exactly one .whl file up to 32 MiB; no pasted archive. ZIP: 10,000 entries, 64 MiB expanded and compression ratio 200 per entry. Unsafe paths, duplicates, CRC failures, encryption, multiple disks and ZIP64 reject. Report: 200,000 JSON values and 10 MiB combined downloads. Any exceeded budget rejects atomically, without a partial audit.
Supports Wheel-Version 1.0 and Metadata-Version 1.1, 1.2 and 2.1–2.6. Exactly one filename-matching dist-info directory must contain METADATA/WHEEL/RECORD. Names compare after dash/underscore/dot normalization; versions compare literally, without inferring PEP440 equivalence. Optional build and compressed tags are compared with WHEEL. Folded/repeated headers, description body and entry points remain literal data.
Checks every archive file against canonical URL-safe Base64 SHA256/384/512 RECORD hashes and byte sizes. Missing, unrecorded, mismatched hash/size or inconsistent metadata means integrityStatus=failed. SHA224 and other unknown hashes are unsupported_hash/incomplete; MD5/SHA1 are forbidden and fail. A failed audit still delivers its complete diagnosis; it does not claim success.
RECORD itself must have empty hash/size. Legacy RECORD.jws/p7s files are signature_not_verified. verified_recorded_payload describes recorded payload checks only, not package authenticity, installation safety, host ABI or platform suitability. Nothing is installed, imported, executed or unpacked to disk.
Table preview: first 200 rows; cells over 2,000 characters show their first 2,000 plus an ellipsis. Above 20,000 report characters, text/copy becomes a summary preview. Full JSON, CSV and HTML remain downloadable, with unsupported hashes and exceptions visible.
Worked example
Example input
Selected file: demo_pkg-1.2.3-py2.py3-none-any.whl (1461 bytes)
Example options
{"secondary":"","params":{"spreadsheetSafe":true},"files":[{"name":"demo_pkg-1.2.3-py2.py3-none-any.whl","type":"application/zip","base64":"UEsDBBQAAAAIADOQRl2Z6IfyFgAAABQAAAAUAAAAZGVtb19wa2cvX19pbml0X18ucHkrKMrMK9FQcvFX8PMPUQgK9VPS5AIAUEsDBBQAAAAIADOQRl2sis5GCQAAAAcAAAAYAAAAZGVtb19wa2cvZGF0YSxxdW90ZWQudHh0y0jNycnn5QIAUEsDBBQAAAAIADOQRl14NdQjlgAAANUAAAAhAAAAZGVtb19wa2ctMS4yLjMuZGlzdC1pbmZvL01FVEFEQVRBXYy9CoMwFEb3PMXFPQF1KWl1crVDC13LRS821Pw0uRZ9+ypCB8fDd87XEmOPjPJBMRnvNBQqF1e0pKEn62V4D+K/5apQpbjRZzKRkmxMYg1xRUqc6qo4Q1j45d3zuxd1lZXqlB0LXoJxg6SZyW1aOnaXPbtP1mJcNNCMNowkoPOOjZuQV0mIhlIXTdgAwojGAa+fSvwAUEsDBBQAAAAIADOQRl0x1dR9WgAAAGkAAAAeAAAAZGVtb19wa2ctMS4yLjMuZGlzdC1pbmZvL1dIRUVMRcg7CoAwEAXAPqfIBVb8dLmA2ImI1lGeGpBd2UTQ22sjljPjBuw0QGMQdrbIclODoT6JOquI8DpvtIQrnQrTiSRqIrUv9jA5m/SE6f3q7HGXxMIgz/c31T8PUEsDBBQAAAAIADOQRl1s0YtXKgAAACsAAAApAAAAZGVtb19wa2ctMS4yLjMuZGlzdC1pbmZvL2VudHJ5X3BvaW50cy50eHSLTs7PK87PSY0vTi7KLCgpjuVKSc3NV7BVAFHxBdnpesk5mVa5iZl5XABQSwMEFAAAAAgAM5BGXe4nb4A4AQAAzAEAAB8AAABkZW1vX3BrZy0xLjIuMy5kaXN0LWluZm8vUkVDT1JEfdDLtkJQAMbxeY/ReJNLLg3OANsldCpJNLFkE6lN7E54+rPOwLDzAr//tz6UPeq4qa6LOC5xSeKYbgbQFQkniF+GnHLjLtBgYtm7wtjY+1bT7uc1WcF3zCzDKxcWsuzKZOwAx8zmaLJQQhLwfNUkQzTpyXwCx4PkfPsBYw1Z3VYQmu9eZZVAzPDLc8at0JKiKpC19nAEpNnEUSzN0TyNyo5QJc7rxUb3Faj4ysQe+iK1sSeprhXh2Bwj/8B39sZx71sBmXu+Fx5UQC1XlqkDjuU/wydL191JvekwYBj1+JMzj/ypQdEQ3IS/peFR0LgVV7MGS50yN0zyDrCM8FnNMGmHuKlLTLq/O6bAWgvKS4VzIXg1t8h8e0gy1XPLi8pYhMZwVND3Dl5c596lYPnPak/Xth4EYPYLUEsBAhQDFAAAAAgAM5BGXZnoh/IWAAAAFAAAABQAAAAAAAAAAAAAALSBAAAAAGRlbW9fcGtnL19faW5pdF9fLnB5UEsBAhQDFAAAAAgAM5BGXayKzkYJAAAABwAAABgAAAAAAAAAAAAAALSBSAAAAGRlbW9fcGtnL2RhdGEscXVvdGVkLnR4dFBLAQIUAxQAAAAIADOQRl14NdQjlgAAANUAAAAhAAAAAAAAAAAAAAC0gYcAAABkZW1vX3BrZy0xLjIuMy5kaXN0LWluZm8vTUVUQURBVEFQSwECFAMUAAAACAAzkEZdMdXUfVoAAABpAAAAHgAAAAAAAAAAAAAAtIFcAQAAZGVtb19wa2ctMS4yLjMuZGlzdC1pbmZvL1dIRUVMUEsBAhQDFAAAAAgAM5BGXWzRi1cqAAAAKwAAACkAAAAAAAAAAAAAALSB8gEAAGRlbW9fcGtnLTEuMi4zLmRpc3QtaW5mby9lbnRyeV9wb2ludHMudHh0UEsBAhQDFAAAAAgAM5BGXe4nb4A4AQAAzAEAAB8AAAAAAAAAAAAAALSBYwIAAGRlbW9fcGtnLTEuMi4zLmRpc3QtaW5mby9SRUNPUkRQSwUGAAAAAAYABgDHAQAA2AMAAAAA"}]}Example output
{"format":"Wheel1.0 archive and RECORD audit","summary":{"files":6,"zipEntries":6,"expandedBytes":848,"verifiedFiles":5,"integrityFailures":0,"unsupportedHashes":0,"unverifiedSignatures":0,"integrityStatus":"verified_recorded_payload","metadataVersion":"2.1","distribution":"demo-pkg","version":"1.2.3","build":null,"packageAuthenticityVerified":false},"filename":"demo_pkg-1.2.3-py2.py3-none-any.whl","distInfo":"demo_pkg-1.2.3.dist-info","filenameTags":["py2-none-any","py3-none-any"],"declaredTags":["py2-none-any","py3-none-any"],"expandedTags":["py2-none-any","py3-none-any"],"metadata":{"headers":[{"key":"Metadata-Version","value":"2.1"},{"key":"Name","value":"demo-pkg"},{"key":"Version","value":"1.2.3"},{"key":"Requires-Dist","value":"requests>=2; python_version>=\"3.8\""},{"key":"Requires-Dist","value":"typing-extensions; python_version<\"3.8\""},{"key":"Summary","value":"example\n continuation"}],"body":"Description plain text.\n"},"wheel":{"headers":[{"key":"Wheel-Version","value":"1.0"},{"key":"Generator","value":"research-fixture"},{"key":"Root-Is-Purelib","value":"true"},{"key":"Tag","value":"py2-none-any"},{"key":"Tag","value":"py3-none-any"}],"body":""},"checks":[{"path":"demo_pkg/__init__.py","status":"verified","algorithm":"sha256","recordedBytes":"20","actualBytes":20,"expectedHash":"sha256=F8c2zPVCDaHJPhFMJQrCClZIt9Dw_04Xg2Xh88L8tzs","actualHash":"sha256=F8c2zPVCDaHJPhFMJQrCClZIt9Dw_04Xg2Xh88L8tzs","sizeMatches":true},{"path":"demo_pkg/data,quoted.txt","status":"verified","algorithm":"sha256","recordedBytes":"7","actualBytes":7,"expectedHash":"sha256=zS7KNTV0HyeorkDDGwxB1AV6enuRKzO5rthkhdHIRnY","actualHash":"sha256=zS7KNTV0HyeorkDDGwxB1AV6enuRKzO5rthkhdHIRnY","sizeMatches":true},{"path":"demo_pkg-1.2.3.dist-info/METADATA","status":"verified","algorithm":"sha256","recordedBytes":"213","actualBytes":213,"expectedHash":"sha256=SxhcJnR7BLHYn_GzYTS3sJMKLlO5dGQ3x5m-V-49HGE","actualHash":"sha256=SxhcJnR7BLHYn_GzYTS3sJMKLlO5dGQ3x5m-V-49HGE","sizeMatches":true},{"path":"demo_pkg-1.2.3.dist-info/WHEEL","status":"verified","algorithm":"sha256","recordedBytes":"105","actualBytes":105,"expectedHash":"sha256=jEDV00BUvf0mfqCD6F5La3jcXU5C292o1F1-WeLXafs","actualHash":"sha256=jEDV00BUvf0mfqCD6F5La3jcXU5C292o1F1-WeLXafs","sizeMatches":true},{"path":"demo_pkg-1.2.3.dist-info/entry_points.txt","status":"verified","algorithm":"sha256","recordedBytes":"43","actualBytes":43,"expectedHash":"sha256=ICVibknf5VupjYGwRd7GBZr36AzhXFyUAdNPDbLKlsc","actualHash":"sha256=ICVibknf5VupjYGwRd7GBZr36AzhXFyUAdNPDbLKlsc","sizeMatches":true},{"path":"demo_pkg-1.2.3.dist-info/RECORD","status":"record_self_unhashed","algorithm":null,"recordedBytes":null,"actualBytes":460,"expectedHash":null,"actualHash":null,"sizeMatches":null}],"issues":[],"entryPoints":"[console_scripts]\ndemo = demo_pkg.cli:main\n","files":[{"path":"demo_pkg/__init__.py","bytes":20},{"path":"demo_pkg/data,quoted.txt","bytes":7},{"path":"demo_pkg-1.2.3.dist-info/METADATA","bytes":213},{"path":"demo_pkg-1.2.3.dist-info/WHEEL","bytes":105},{"path":"demo_pkg-1.2.3.dist-info/entry_points.txt","bytes":43},{"path":"demo_pkg-1.2.3.dist-info/RECORD","bytes":460}],"unverifiedExceptions":["RECORD self entry has no hash/size","legacy signatures are not verified","no package authenticity/ABI/security/installation verdict"]}When something does not work
Use the producer’s complete original wheel and filename. Check the unique dist-info directory, required headers, tags, canonical RECORD CSV and paths. Obtain a trusted replacement for failed hashes; do not rewrite hashes to hide a mismatch. For exceeded budgets, generate a smaller archive with the producer.
Frequently asked questions
Why can a failed hash still have downloads?
The download is a failed diagnosis: integrityStatus is explicitly failed. Each declaration and observed value remains available for investigation.
Does this prove a wheel is safe?
No. RECORD is not a trusted signature. This tool does not assess code safety, author identity or your machine ABI.
Why is SHA224 unsupported?
This contract implements SHA256/384/512 only. SHA224 is explicitly unsupported, so its files are never claimed fully verified.
Documentation & further reading
Related tools
JSON formatting workspace
Format or minify strict JSON, sort object keys, and encode or decode strings while preserving raw number tokens.
Regex tester
Try a pattern and see what it matches in your text.
Compare text
See what changed, side by side.
HTML formatter
Format HTML indentation so its structure is easier to read.