Five steps, in order:
- List every claim, word for word.
- Pair each claim with its source and the exact words that carry it.
- Let a script fetch the source and look for those words.
- Sort each claim into one of five states.
- Read each found quote against its sentence.
Steps 3 and 4 are mechanical, which is why I give them to a script: it runs them the same way every time and leaves a record anyone can re-run.
A script takes the two mechanical steps; a reader takes the other three
All five are about sentences that lean on a document: a study, a statistic, a filing, a standard. A figure the report computed from your own data can go through the same match against the query output it came from. That proves it was copied correctly and says nothing about whether it was computed correctly; for that, use the checks in How to check the numbers in an AI-generated report.
Why a citation proves nothing on its own
A reference list looks like evidence whether or not anything stands behind it. In a 2023 study in Scientific Reports, Walters and Wilder had ChatGPT write short literature reviews on 42 topics and looked up the 636 references it gave. 55% of GPT-3.5’s references and 18% of GPT-4’s were fabricated: no such work exists. Most of the invented articles, books and web pages named a real journal, publisher or organisation, so checking that the journal exists would have passed them.
Those are 2023 models, and the newer of the two already invented far fewer. A real reference is still not a supporting one. A 2025 study in Nature Communications tested seven AI models on 800 medical questions, checking 58,000 pairs of a statement and a source the model cited. Even for GPT-4o with web search, about 30% of individual statements were not supported by the sources it cited. Support was judged by the authors’ own automated checker, which agreed with a consensus of three US-licensed doctors 89% of the time. Medical questions are not a sales report, and I would not carry the 30% over to one. The shape of the failure does carry over: a real page, cited under a sentence it does not say.
The newer model invented far fewer references; a real one still often failed to support its statement
GPT-3.5, 2023
55%
of its references fabricated: no such work exists
GPT-4, 2023
18%
of its references fabricated
With web search, 2025
About 30%
of GPT-4o’s statements not supported by the sources it cited
The US National Institute of Standards and Technology lists the check among its suggested actions for generative AI: review the sources and citations in what the system produces, before it is deployed and while it runs (NIST AI 600-1, action MS-2.5-003).
1. List every claim, word for word
A claim is any sentence a source could contradict: a figure, a date, a ranking, a “studies show”. Copy each one out exactly as the report prints it. Paraphrasing here is how a claim gets softened before anyone has checked it, and the softened version checks out more easily than the one your reader will see.
One reader misses claims, so I would have two or three list them separately and keep everything any of them found, since a claim left off the list is never checked. Then hold the list against the report, word for word. A listed claim the match does not find there has three possible readings, and the first is ruled out before the others: the matcher failed on words that are there (a curly quote mangled on the way in is enough), which one look at the report settles. Otherwise it is a paraphrase or a sentence the report never wrote, and it is flagged, never quietly dropped.
2. Pair each claim with its source and its quote
For each claim, write down two things: the document it rests on, and the exact words in that document that carry it. The document should be the one that first published the figure, not a page repeating it. The words should be copied from the source, never typed from memory.
A claim with no document gets no quote. It is a finding already, before anything is fetched.
3. Let a script fetch the source and look for the quote
The script downloads the source, takes the text out of the web page or the PDF, and searches it for the quoted words. Before searching, it folds away differences that rarely change meaning, on both sides: curly against straight quote marks, one kind of dash against another, line breaks and spacing, capital letters, invisible characters, and special forms of a character into the plain one. So a quote that runs across two lines of a PDF usually still matches, and a quote with a word or a digit changed inside it does not. A raised or lowered digit, such as the 2 in 10², keeps its own form, and so does a fraction, so on a web page a quote reading “102 units” does not match “10² units”. The first rare case is a PDF: the text a PDF gives up has already lost the raised ², so there the same quote matches.
The second rare case is a second try. When the quote is not found, the script searches again with a leading >, |, # or // taken off each line of the source: the marks a quoted block or a comment repeats on every line, which a quote copied across those lines leaves out. So a source line that starts “> 5%”, more than 5%, can match a quote that says 5%.
The third rare case is in the search itself. It looks for the quoted words anywhere in the source’s text, so a quote can begin partway through a number. Quote the study in step 5 as “8% of the GPT-4 citations are fabricated” and it comes back found, because the source reads “just 18% of the GPT-4 citations are fabricated”. A figure at the very start or end of a quote is worth reading against the source yourself.
Line breaks are a blind spot. Given the NIST action above word for word, the script used to come back not found: the PDF breaks “pre-deployment” at its hyphen across two lines, and after folding the source read “pre- deployment”, with a space the quote does not have. It now joins a line that ends in a hyphen to the next with the hyphen kept, and finds the action. A word split only to fill a line still defeats it: “moni-” over “toring”, quoted as “monitoring”, comes back not found, because the text cannot tell that hyphen from one the word keeps, as in “re-lease”. That is why a quote that comes back not found is worth one look before anyone is told they made it up.
Small differences match, three times too generously, and a line break can still defeat the search
The script also writes down what it did: the address it fetched and when, whether the page answered, the words it matched, where they sit in the source’s text, and how that text was folded. Anyone holding that record and the script can run the same check again, without me or the agent that ran it first, and disagree with it.
4. Sort each claim into one of five states
Each claim ends in exactly one of these. The state follows from what the script found, or from there being nothing to look up, never from anyone’s opinion of the claim.
Three questions about what happened decide every state
The five states as a table
| State | What happened | What happens next |
|---|---|---|
| Found and quoted | The source opened and the quoted words are in it. | The claim goes on to step 5. |
| Quote not in the source | The source opened and the quoted words are not in it. | Look once, to rule out the matcher. Then the sentence is corrected to what the source says, moved to a source that does say it, or comes out. |
| No source | The sentence names no document to check. | It gets a source or comes out. |
| Source not found | The link is dead: the server says the page does not exist, or the address leads nowhere. | The claim comes out until it is sourced to a document that opens. |
| Source would not open | A paywall, a login, a refusal, a server error, a timeout, or a deep link that lands on the site’s home page. | No mark against the report and no pass either: the claim stays unchecked, and is listed as unchecked. |
Two of these must never be merged. “Quote not in the source” means the source was read and does not say it: the signature of a made-up or misremembered quote. “Source would not open” says nothing about the report at all. The US Bureau of Labor Statistics’ page on data scientists, a public page, refused the script on 13 October 2026. Filed as a failure, a correctly cited figure from it would read as invented; filed as found, it would pass a figure nobody checked.
A worked example
Let’s take a report from the online coffee shop of our demos, deciding whether to let an AI assistant draft its market research. The shop does not exist and neither does its report. One sentence in it cites the study above.
| Field | Record |
|---|---|
| Sentence | “AI research assistants make up 18% of the sources they cite, so checking a sample of the references is enough.” |
| Source | Walters and Wilder, Scientific Reports, 2023 |
| Quote | “just 18% of the GPT-4 citations are fabricated” |
| Fetched | 13 October 2026; the page answered normally |
| Where | In the study’s abstract |
| State | Found and quoted |
The quote is real, so the claim moves on. Had the report quoted the study as saying 15%, the same run would have returned “quote not in the source”.
5. Read each found quote against its sentence
Now read the two side by side. The number is right. The quote is about one model, GPT-4, writing short literature reviews on 42 topics in 2023; the sentence is about “AI research assistants” in general, and it draws a conclusion the study never reaches. With nearly one reference in five invented, a sample of the references is the last thing I would settle for. The script sees none of this. It returned the same state for that sentence as for my own use of the study above, and only one of the two says what its quote says.
One quote, one state, two verdicts: only a reader tells these sentences apart
A found quote can still fail its sentence in four ways I look for:
- A dropped condition: a result that held for one model, one market or one year, cited as if it held everywhere. The invented sentence fails this way.
- The wrong comparison: an effect measured against one group, cited as if against another.
- A win over a weak alternative, read as a win over doing nothing.
- A repeater: the words are on the page, but the page copied the figure from somewhere else and may have changed it on the way.
Where two sources disagree, both stay in the record and neither is picked. The disagreement goes to whoever owns the decision, with both sources beside it.
So a report whose claims all come back found and quoted has passed the cheap half of the check. Its quotes are in their sources, bar the rare cases in step 3. Whether they say what the report says is still open until someone has read them.
For the same idea applied to a report’s arithmetic, the break-a-number demo lets you damage a figure in a small invented report and shows which checks catch it and which still pass.
How FinDaS does it
At FinDaS, AI agents build the analysis and write the report. Before any reviewer reads it, this check runs on it: agents that did not write it list the claims, each is sorted into the five states, and a claim that fails (no source, a dead source, or a quote not in it) goes back to the agents to fix, then through the check again; two fix rounds that fail on the same kind of problem stop the work, and I decide. Step 5 is judgement: a review by an agent, and on anything you will act on, that review is a panel of three reviewer agents and a judge. The judgement calls are mine, and I sign what you act on, such as a model going live or a decision memo. Each deliverable carries a short note saying which checks ran on it. The steps are on how it works.
Sources
- Walters and Wilder, Fabrication and errors in the bibliographic citations generated by ChatGPT, Scientific Reports 13, 14045, September 2023.
- Wu, Wu, Wei and others, An automated framework for assessing how well LLMs cite relevant medical references, Nature Communications 16, 3615, April 2025.
- National Institute of Standards and Technology, NIST AI 600-1, Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profile, July 2024.