Skip to main content

xlsx-provenance

Status Python License Last Commit

Fingerprint .xlsx files for authorship and authenticity. Tells you whether a workbook was actually authored in Excel, or generated by a library (openpyxl, xlsxwriter, Aspose, ClosedXML, EPPlus, SheetJS, ...) or another office suite (LibreOffice, OnlyOffice, WPS, ...).

Stdlib-only Python. No third-party dependencies.

Why

An .xlsx is a zip of XML. Every authoring tool leaves fingerprints: different Application strings, different fileVersion attributes, different presence/absence of calcChain.xml, theme1.xml, printerSettings*.bin, <HeadingPairs>, <TitlesOfParts>, cellXfs count="" attributes, and so on.

This tool reads those fingerprints and gives you a per-file verdict you can act on.

Install

git clone https://github.com/jtannahill/xlsx-provenance.git ~/xlsx-provenance
ln -s ~/xlsx-provenance/xlsx-provenance ~/bin/xlsx-provenance
# ensure ~/bin is on PATH

Or just run the script directly:

~/xlsx-provenance/xlsx-provenance some-file.xlsx

Usage

xlsx-provenance file1.xlsx [file2.xlsx ...]
xlsx-provenance *.xlsx
xlsx-provenance --json file.xlsx           # machine-readable
xlsx-provenance -v file.xlsx               # show full signal breakdown
xlsx-provenance -q *.xlsx                  # one line per file
xlsx-provenance --no-color file.xlsx       # plain output

Exit code is 0 if every file is verdict EXCEL_* or a non-Excel office suite (LIBREOFFICE, ONLYOFFICE, etc.). It is 1 if any file came back from a programmatic library (OPENPYXL, XLSXWRITER, ...) or as SUSPECT / UNKNOWN / MISSING / INVALID. Useful in CI.

Verdicts

Verdict Meaning
EXCEL_MAC Microsoft Macintosh Excel. Authentic Excel for Mac
EXCEL_WIN Microsoft Excel. Authentic Excel for Windows or Online
EXCEL_OTHER Some other Excel variant string, but Excel fileVersion confirmed
EXCEL_LIKELY No explicit Application, but enough Excel-only artifacts (calcChain, fileVersion appName=xl, real theme, printerSettings, VBA, threaded comments, etc.) to be confident
OPENPYXL, XLSXWRITER, ASPOSE, CLOSEDXML, EPPLUS, OPENXML_SDK, SHEETJS, SPREADJS, SYNCFUSION, GEMBOX, SPIRE, LUCKYSHEET, PYTHON_XLSX Application string explicitly declared a generation library
LIBREOFFICE, ONLYOFFICE, OPENOFFICE, GNUMERIC, CALLIGRA, WPS_OFFICE, APPLE_NUMBERS, GOOGLE_SHEETS Authentic but non-Excel office suite
SUSPECT No Application and no fileVersion. Looks tampered or hand-built
UNKNOWN Couldn't classify
MISSING File doesn't exist
INVALID Not a valid zip / corrupted

Signals examined

  • docProps/app.xml: Application, AppVersion, Company, Manager, DocSecurity, presence of HeadingPairs + TitlesOfParts (Excel-only, openpyxl skips)
  • docProps/core.xml: creator, lastModifiedBy, created / modified timestamps (and their delta; < 1s smells automated), lastPrinted
  • xl/workbook.xml: <fileVersion appName="xl" rupBuild="..."> (Excel-only), workbookPr/@codeName, defined names, sheet count
  • Zip artifacts: calcChain.xml (Excel writes, libraries usually skip), theme/theme1.xml size (Excel: ~6796–8390 B; openpyxl: < 4 KB), printerSettings*.bin, vbaProject.bin, pivotTables/, pivotCache/, connections.xml, externalLinks/, charts/, drawings/, comments*.xml, threadedComments (Excel 365), tables/, queryTables/
  • xl/styles.xml: Excel often omits count="N" on <cellXfs>; openpyxl always includes it. Excel writes <tableStyles>, <indexedColors>.
  • xl/sharedStrings.xml: uniqueCount attribute presence
  • [Content_Types].xml: number of overrides, presence of theme override

The verdict combines a hard match on the Application string with a soft score (0–14) over the structural signals. High score with no library declaration → EXCEL_LIKELY.

Examples

Pretty (default):

=== model.xlsx ===
  [EXCEL_MAC] Excel signal score 11/14  (confidence: high)
  application    Microsoft Macintosh Excel  /  AppVersion 16.0300
  identity       creator=''  lastModifiedBy='james tannahill'
  fileVersion    appName='xl' lastEdited='7' lowestEdited='7' rupBuild='10503'
  workbook       sheets=11  definedNames=0  codeName=None
  artifacts      calcChain, theme1(6798B), printerSettings, drawings
  styles.xml     count attr omitted, tableStyles, indexedColors
  content-types  18 overrides, theme=True
  zip            22 entries

Library tell:

=== generated.xlsx ===
  [OPENPYXL] Application explicitly declares openpyxl  (confidence: high)
  application    Microsoft Excel Compatible / Openpyxl 3.1.5  /  AppVersion 3.1
  identity       creator=''  lastModifiedBy='someone'
  fileVersion    <missing>
  ...

JSON for piping into other tooling:

xlsx-provenance --json *.xlsx | jq '.[] | select(.verdict == "OPENPYXL") | .path'

How to "fix" an openpyxl-generated file

Open it in real Excel and File → Save As (overwrite or new name). Excel rewrites every metadata field (Application, fileVersion, calcChain, theme) to its native fingerprint. Editing docProps/app.xml by hand only fixes the visible Application string and leaves the deeper structural tells intact.

License

MIT

Metadata

Release files for xlsx-provenance 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xlsx-provenance 1.0.0
File Size Uploaded
xlsx_provenance-1.0.0.tar.gz 9.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xlsx-provenance 1.0.0
File Interpreter ABI Platform
xlsx_provenance-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 19.2 kB

Release files / xlsx_provenance-1.0.0.tar.gz

Download URL xlsx_provenance-1.0.0.tar.gz
Size 9.0 kB
Tags Source
SHA-256 checksum
How to use checksums
cd39405c3098f5a581427c125e53f7a23b463de0667e8790ec66d981eda39362
BLAKE2b-256 checksum
How to use checksums
8613d62818ac6f0af88343d8957584b7f91221395cfc7ebaf29cd8527c45f10c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / xlsx_provenance-1.0.0-py3-none-any.whl

Download URL xlsx_provenance-1.0.0-py3-none-any.whl
Size 10.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d223d6c2abb2f5e89bbc779cbacede54e4b4ad5843f306195c98487276e9985
BLAKE2b-256 checksum
How to use checksums
e190c1bbff1bb74bf7e53a49b9aaf5c0b515b6e34119c426acabdf1bd05d3667
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

1.1.0

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page