Skip to content

Repository files navigation

SynthCheck

Is this photo real, or did a machine make it? SynthCheck takes an image file apart and shows you the evidence — Content Credentials, generator metadata, camera EXIF, and the fingerprints left in the file's own structure.

Live at synthcheck.app. Free, no account, no limits.

Nothing is uploaded. Every byte is parsed by JavaScript in your own browser. There is no backend to send anything to — switch off your internet and the tool still works, which is the easiest proof there is. This repository exists so that claim can be checked rather than believed.


What makes it different

Most detectors show a confidence percentage. Ask where the number comes from and you will not get a straight answer. SynthCheck shows the evidence and grades it, and says plainly when the honest answer is "cannot tell".

It verifies C2PA signatures locally. Other tools read a Content Credentials manifest and repeat what it claims. SynthCheck checks the mathematics — in the browser, with the image never leaving the device. As far as we know it is the only tool that does this without an upload.

Verification answers three questions that fail separately, so they are reported separately:

Question What is checked What a pass proves
Is the signature valid? COSE_Sign1 verified via WebCrypto against the certificate in the manifest The manifest was signed by the holder of that key and has not been altered
Does it bind to this image? The c2pa.hash.data hash recomputed over the image bytes, honouring the manifest's exclusion ranges The signed record describes these exact bytes — it was not lifted off another file
Who signed it? X.509 subject, issuer, validity, and internal chain consistency Only what the certificate asserts. Confirming the signer is genuinely that party needs a trust list, which this tool does not ship — and it says so

The middle row is the one that matters and the one naive readers skip. A manifest transplanted from a genuinely signed photo onto a fake keeps a perfectly valid signature. Anything that asks "is it signed?" instead of "does the signature cover these bytes?" waves that through. There is a test fixture for exactly this case, and it must fail.

What it reads

  • C2PA / JUMBF Content Credentials — parsed, then cryptographically verified
  • IPTC DigitalSourceTypetrainedAlgorithmicMedia and its relatives
  • XMP packets, including generative-edit markers
  • Generator leftovers — Stable Diffusion, ComfyUI, InvokeAI and Fooocus write the prompt, seed, sampler and model name into the file, and nobody removes it
  • Camera EXIF — body, lens, exposure, timestamp, GPS
  • Structural fingerprints — this is the part that still works after a social platform has stripped every scrap of metadata: diffusion-preset output dimensions, JPEG quantization tables no camera firmware would write, progressive coding and thin Huffman tables that betray a software encoder

Formats: JPEG, PNG, WebP, AVIF, HEIC/HEIF, TIFF. PNG zTXt/iTXt chunks are inflated, which most tools skip.

What it cannot do

Stated here as plainly as on the site, because a detection tool that oversells itself is worse than none.

  • No pixel classifier. We do not guess from pixels and will not invent a percentage.
  • SynthID is out of reach. Google DeepMind's watermark lives in the pixels and has no public reader.
  • Trust lists are out of scope. We prove a signature is intact and belongs to the image. Whether the certificate belongs to the company it names is a separate question needing data we do not ship.
  • A clean file is not a real photo. Metadata removal is trivial — a screenshot does it by accident. Absence of an AI marker is never evidence of authenticity. Markers are strong evidence in one direction and none at all in the other.

Running it

npm install
node build.js        # generates ./site — 71 pages across 5 locales
npm test             # parser fixtures + the built site executed in a real DOM
node test/audit.mjs  # hostile inputs, XSS, CSP, performance budgets

Open site/index.html, or node serve.js for a local server.

The test fixtures

test/make-c2pa.mjs builds genuinely signed images with real certificates, plus three that are broken in one specific way each:

Fixture Expected
14_c2pa_signed.jpg Origin verified
15_c2pa_tampered_pixels.jpg One image byte flipped after signing — binding fails
16_c2pa_transplanted.jpg Manifest moved to a different photo — signature still valid, binding fails
17_c2pa_broken_claim.jpg Claim edited after signing — signature fails

A verifier that only ever sees valid input is not a verifier.

Layout

engine.js     container parsing, metadata extraction, structural analysis
c2pa.js       JUMBF, CBOR, COSE_Sign1, X.509 — the cryptographic verification
build.js      static site generator, 5 locales
src/          app.js (UI), app.css, i18n/*.json
content/      markdown for articles and legal pages
test/         fixtures and the two test suites

No framework, no bundler, no runtime dependencies. The whole site is 39 KB over the wire.

Privacy

There is no server, so there is nothing to log. Analytics (Microsoft Clarity) loads only after consent, and the panel showing analysis results is excluded from recording. The map link for GPS coordinates is a link, never an embedded tile — coordinates leave the browser only if the visitor clicks it.

Licence

GNU AGPL-3.0-or-later. You may read, audit, modify and share it. If you run a modified version as a service, you must publish your changes.

SynthCheck reads and removes nothing. It will never gain a feature for stripping provenance markers.

About

Browser-only image provenance checker. Verifies C2PA Content Credentials locally - nothing is uploaded.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages