The invoice read $186,000 for a twelve-week billing service. The repo had 41 commits, and the fourth was a squashed import of a public GitHub project I found in about twenty minutes. The contractor had done real work on top of it. They had also deleted the NOTICE file, which turned a manageable licensing conversation into a legal one.
That was 2022. I have run some version of the same audit on eleven contracted codebases since, and the failure modes repeat. So does the fix, which is boring and procedural and starts long before anyone opens a code editor.
Verify contractor code originality by answering three separate questions with three separate tools: is this code theirs, is it legally clean, and was it written by a person. Run the checks at three points in the engagement (signing, weekly, final tag), and put the right to audit into the statement of work before the first invoice.
Three things "original" is hiding
Clients ask me to check whether contractors "copied code." That single question is really three. They have different evidence, different tools, and different consequences.
| Failure mode | What it looks like in the repo | What catches it |
|---|---|---|
| License-stripped reuse | Apache 2.0 or AGPL source with headers removed, or a vendored library with no version pin | License and provenance scan, plus a dependency tree diff |
| Bulk AI generation | Large first commits, uniform comment density, tests that assert nothing meaningful | Per-file AI generation scoring, not a repo-wide average |
| Recycled from another client | Domain logic that does not match your spec, or naming from a different industry | Similarity check against your own history and the open web |
The first one costs money and sometimes the product. The second one costs you a maintainable codebase in eighteen months. The third one is an IP dispute waiting for a bad quarter.
The six-step contractor code originality checklist
1. Contract language before the kickoff
Nothing else on this list works without clause language, because a contractor who declines an audit clause has told you something useful. I ask for four sentences in the SOW, and I have never had a competent shop push back hard:
- Delivered code is original or properly licensed, with license text and NOTICE files intact.
- Client has the right to run automated originality, license, and AI-generation scans on all repositories and commits.
- Contractor will disclose any pre-existing components, including internal libraries and open-source dependencies.
- Final payment is contingent on a clean scan, with a defined remediation window.
That last line matters more than the other three combined. Everything else is conversation until money is attached.
2. Repository access from week one
The single most common mistake I see is a CTO who gets read access to the deliverable repo in week eleven. Weekly access to commits, not just the main branch, gives you the history you need. It also changes behavior on its own. Contractors who know someone reads the commit log write better commit messages.
Ask for the repo, the dependency lockfiles, and a one-page component disclosure. If they use an internal shared library, you want its name on a list, not discovered six months later.
3. A license and provenance scan on the final tag
Run this against the release tag, not HEAD, because that is the artifact you ship. ScanCode 32.x does solid license identification on source trees, and FOSSA or Snyk handles the transitive dependency graph. What neither does well is tell you where a suspicious block came from. That is provenance, and it is a different question.
I exported our own repo history and ran it through a source code plagiarism checker with a web corpus, and it surfaced three functions that matched a Stack Overflow answer from 2016 verbatim, including the typo in the variable name.

4. An AI generation scan, separated by file
A repo-level AI score is close to useless. A 900-file backend will average out to 12% whether two files were generated or two hundred were. You want per-file scores and a list sorted by suspicion, because the remediation is a conversation about specific files, not the whole delivery.
What I look for in the top files: comment density that does not match the rest of the repo, defensive error handling on code paths that have no callers yet, and test files that import a mocking framework and then assert nothing. Those are people-shaped signals, not model-shaped ones. A contractor who leans on Copilot for boilerplate will show scattered low scores. Someone who prompted a model to build a service will show a cluster of files above 70% with almost no edits afterward.

Codequiry is the one tool I have used that returns peer similarity, web matches, and per-file AI scores from a single run, and its REST API is what made step six possible in a CI pipeline instead of a spreadsheet. The AI-written code detector breaks scores down file by file with written indicators, which is the part that survives a difficult conversation with an account manager.
5. A similarity check against your own codebase
Contractors reuse their own work. That is usually fine and occasionally not. If the same shop has built for a competitor of yours, a similarity run against your repository history catches the overlap before it becomes a discovery problem.
This is also where rename-and-reformat tricks show up. Token and AST comparison ignores what the variables are called:
// Delivered
public int calc(List<Integer> items) {
int acc = 0;
for (int i : items) if (i % 2 == 0) acc += i;
return acc;
}
// Original, found on a public repo
public int sumEven(List<Integer> nums) {
int total = 0;
for (int n : nums) if (n % 2 == 0) total += n;
return total;
}
Text matching scores those as different files. A structural comparison scores them as the same nine tokens in a row. If you are evaluating engines on this dimension, the source code plagiarism checker walkthrough explains which normalization steps actually hold up under reformatting.
6. A human read of the top five files
Automation sorts the pile. It does not make the call. I read the five highest-risk files myself before I write the memo, and about a third of the time I downgrade the finding because there is a legitimate explanation: a contractor who published their own utility library, or a generated ORM model that everyone uses.
A scanner's job is to make the top of the pile short enough that a human can actually read it. Any vendor who tells you the tool makes the decision for you is selling you a lawsuit.
Wiring it into the delivery gate
A scan that depends on someone remembering to run it is not a control. Ours runs on the release tag, blocks the pipeline, and posts to the project channel. The shape of the call matters less than the fact that a failing exit code stops the deploy:
# delivery-gate.sh, runs on the release tag
codequiry scan \
--check "acme-billing-final" \
--language java \
--path ./src \
--engines peer,web,ai \
--fail-on ai_score>0.40,web_score>0.15
The 0.40 threshold is a number I set in 2023 and nobody has touched since, which should tell you how much calibration went into it. Tune yours against your own accepted deliveries rather than copying mine.

What this does not do
None of this proves authorship. If a contractor pastes AI output into a file and then spends two days restructuring it, the resulting code is genuinely theirs in the sense that matters legally, and the score will probably still be elevated. That gap is real and I have not found a tool that closes it. We have not tested AI scoring past a few hundred files in a single delivery either, and the sample is smaller for languages with heavy framework boilerplate like TypeScript React and Go.
What the checklist does is move the discovery from a legal review six months after launch to a Tuesday afternoon in week four, when the contractor still has budget to fix it and you still have leverage. That is the whole return.
If you are putting this in front of a procurement team next quarter, start with how Codequiry compares to MOSS for the methodology question, then get your clause language signed and run a code plagiarism checker on the first delivery before the invoice clears.