What does a verified Git commit signature prove, given that author fields are free text?
answer
- Look at what a commit object actually contains
- Two identity lines, neither one checked
- The signature covers the whole object
- Signer and author are different fields
- A key is not automatically a person
basics
~20 sIt proves the holder of that key produced that exact commit object and it has not changed since. Git's author and committer fields come from local config and are unverified text, so the signature attests the signer, never the person named as author.
solid answer
~50 sA commit object contains a tree hash, parent hashes, an author line, a committer line and a message — and the author and committer names and emails are just whatever `user.name` and `user.email` were set to on the machine that made it. Nothing checks them. When you sign, the signature covers the whole object, so a valid signature proves that whoever controlled the signing key produced this exact commit — that tree, those parents, that message, and those identity lines as written — and that no byte has changed since. It does not prove the person in the author field wrote the code, that the key belongs to a particular human (that mapping comes from your keyring or allowed-signers file), or that the change is any good. Anyone can set the author to a colleague's name and sign with their own key; the signature is still valid, and it identifies the signer, which is exactly why tools display the signer separately from the author.
code
console · 10 lines$ git cat-file -p HEAD
tree 7f2c1a...
parent 91ab33...
author Ada Lovelace <[email protected]> 1699999999 +0000
committer Real Person <[email protected]> 1699999999 +0000
gpgsig -----BEGIN SSH SIGNATURE-----
...
-----END SSH SIGNATURE-----
fix: clamp retry backoffgo deeper
Remember that user.name and user.email are just local settings Git copies into the commit, so authorship on an unsigned commit is a claim rather than proof.
Explain that the signature covers the whole commit object — tree, parents, identity lines, message — so it binds the signer to that exact content, and that signer and author are separate fields.
Enumerate the gaps with precision and show you would inspect signer alongside author, and that you know verification is meaningless without a maintained key-to-principal mapping.
Own the policy framing: state what the organisation is actually trying to prove about provenance, where that check runs, and why signing without a maintained trust list and verification step buys nothing.
## What is actually in a commit Run `git cat-file -p HEAD` and you see the whole commit object: a `tree` line, zero or more `parent` lines, an `author` line with a name, email and timestamp, a `committer` line with the same shape, an optional `gpgsig` header holding the signature, a blank line, and the message. The author and committer lines are ordinary text. Git fills them from `user.name` and `user.email` in configuration, and it never checks them against anything — there is no registry, no authentication step, nothing. `git commit --author="Ada Lovelace <[email protected]>"` writes exactly that, and `GIT_COMMITTER_NAME` and `GIT_COMMITTER_EMAIL` set the other line. Uncontroversially, then, an unsigned commit's stated authorship is a claim by whoever made it, not evidence. ## What signing adds Signing computes a signature over the commit object's content and stores it in the object's header. Because the object id is the hash of that content, the signature and the identity of the commit are bound together: change the message, the tree, a parent, or the author line, and you get a different object whose signature no longer validates. So a verified signature supports exactly this statement: *the holder of key K produced this exact commit object, including its author and committer lines as written, and nobody has altered it since.* Everything else people believe about signed commits is an addition on top of that statement, and each addition needs its own justification. ## The gaps, stated precisely **Signer is not author.** The two are independent fields. A commit whose author line says a colleague's name, signed with your key, verifies perfectly — it just verifies as *your* signature. This is why `%GS` (signer) is a separate placeholder from `%an` (author), and why any policy that says "commits must be signed" without also comparing signer to the claimed identity has left the interesting hole open. **Key is not person.** Verification tells you the signature matches a key. Which human or system that key represents is a mapping you supply — an OpenPGP keyring with trust settings, or a `gpg.ssh.allowedSignersFile` listing principals against public keys. Get that mapping wrong, or accept an unknown key, and the verification is arithmetic without meaning. This is also why an untrusted-but-valid signature has its own status code rather than being reported as good. **Signed is not reviewed, and not safe.** A signature says who produced a change, not that the change is correct, tested, or benign. It is a provenance mechanism, not a quality one. **A signed tip does not mean signed history.** A commit names its parents by hash, so accepting a tip commit accepts that ancestry as content. But nothing requires the ancestors to be signed by anyone. "The tip is signed" and "every commit is signed" are different assertions, and they need different checks. ## Why the distinction matters in practice The common story is a repository where anyone can push and where an attacker — or just a careless script — creates commits attributed to a trusted maintainer. Unsigned, that attribution is free. Signed, the attacker must either use a key you trust or produce a commit that fails verification, so a verifier that compares the signer against a trust list can tell fabricated attribution from the real thing. The converse story is a team that turns on signing and believes the problem is solved while the verification side is never configured — every commit reports as uncheckable, and the signatures are decoration. Signing without verification changes nothing about anyone's security posture. ## What to do with the distinction When you inspect a commit's provenance, look at the signer, not the author: `git log --pretty="%h %an <%ae> | %G? %GS"` puts both on one line and makes divergence obvious. When you define a policy, state it in terms of signers and a trust list. When you rely on a signature, be sure the key-to-principal mapping is something you actually maintain — rotation and revocation are part of the mechanism, not an afterthought. ## Interview framing Start from the object: name the fields, point out that author and committer are unverified config values, then state what the signature binds and enumerate the four gaps — signer versus author, key versus person, provenance versus quality, tip versus history. That order shows you reasoned from Git's data model instead of reciting a slogan.
- How would you detect a commit whose author line does not match its signer?Render both and compare: `git log --pretty="%h %ae %G? %GS"` shows the author email beside the signature status and signer. A policy check walks the range, requires a good status, and asserts that the signer maps to the claimed identity through your trust list — signature validity alone never establishes that.
- Does signing the tip of a branch say anything about the commits beneath it?It fixes their content: the tip names its parent by hash, and each parent names its own, so accepting the tip accepts that exact ancestry. It says nothing about who produced those ancestors or whether they were signed. Requiring every commit to be signed is a separate check over the whole range.
- If author fields are unverified anyway, what does signing actually change?It moves the claim from unfalsifiable to checkable. Unsigned, anyone can attribute a commit to anyone. Signed and verified against a maintained trust list, a fabricated attribution either lacks a signature or carries one from a key you do not trust, so a verifier can distinguish the cases mechanically.
saying these in an interview costs you the question
- Says a signature proves the named author wrote the code
- Believes Git validates user.email at commit time
- Assumes a valid signature implies the change was reviewed
- Thinks a signed tip means all ancestors are signed
- Treats key identity as automatic rather than a maintained mapping