How Code Fingerprints Catch GPL License Violations

The High Cost of GPL Violations

In 2007, the Software Freedom Conservancy filed a lawsuit against VMware for using Linux kernel code (licensed under GPLv2) inside its proprietary ESXi hypervisor without releasing the corresponding source code. The case, Hellwig v. VMware, dragged on for nearly a decade and ended in a settlement only after public evidence proved that VMware’s vmklinux module contained literal copies of GPL-licensed header files and data structures. VMware had renamed variables, rearranged function order, and even swapped file names — but the structural fingerprints of the code remained intact.

This is the reality of open-source license compliance. A single developer pulling in a GPL’d function from GitHub can infect an entire proprietary product with copyleft obligations. And because license violations often stem from code copy-pasted from memory or heavily refactored, traditional grep-based searches for license headers are useless.

Automated license compliance detection now relies on the same techniques used to catch student plagiarism: code fingerprinting, AST comparison, and tokenized similarity scoring. These methods can detect GPL code even after variable renaming, function reordering, and comment removal — precisely the tactics used to hide provenance.

How Code Fingerprinting Works

Fingerprinting turns source code into a set of hashed substrings that are resistant to cosmetic changes. The most widely used algorithm for this is winnowing, popularized by Schleimer, Wilkerson, and Aiken in 2003 for the MOSS plagiarism detection system. The core idea is simple:

  1. Tokenize the source into a sequence of lexical tokens (ignoring comments, whitespace, and variable names).
  2. Divide the token sequence into overlapping k-grams of length k (typically 5 tokens).
  3. Hash each k-gram to produce a fingerprint.
  4. Select a subset of hashes (e.g., the minimum hash in a sliding window of size w) to keep the fingerprint compact.

The result is a small, noise-tolerant set of hashes that represents the code’s structure. Two files that share many of the same hashes are almost certainly derived from the same original source, even if variable names, formatting, and comments differ.

Consider this GPL-licensed kernel function (simplified):

/* SPDX-License-Identifier: GPL-2.0 */
int kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) {
    struct page *page = NULL;
    if (unlikely(cachep->flags & SLAB_RECLAIM_ACCOUNT)) {
        page = alloc_pages(flags | __GFP_RECLAIM, cachep->gfporder);
    } else {
        page = alloc_pages(flags, cachep->gfporder);
    }
    if (unlikely(!page))
        return NULL;
    cachep->num = page_private(page);
    return page_address(page);
}

Now take a version that a proprietary vendor might produce after renaming and reformatting:

int my_alloc(struct my_cache *c, mem_flags f) {
    struct page *p = 0;
    if (likely(!(c->fl & FLAG_RECLAIM))) {
        p = alloc_mem(f | MEM_RECLAIM, c->order);
    } else {
        p = alloc_mem(f, c->order);
    }
    if (unlikely(!p))
        return 0;
    c->count = get_page_private(p);
    return page_addr(p);
}

Tokenization strips identifiers and literals, leaving only the token sequence: int struct if else struct return and so on. The k-grams of the original and the derivative will match almost perfectly. A winnowing fingerprint with k=5 and w=10 will produce dozens of identical hashes. The license header is never checked — the structural skeleton of the code betrays its origin.

AST-Based Similarity for Copyleft Detection

Token-based fingerprinting is fast and effective, but it can miss cases where the copied code has been restructured at a higher level — for example, splitting a function into two, inlining helper calls, or reordering conditionally executed blocks. For those scenarios, abstract syntax tree (AST) comparison is more robust.

An AST parser builds a tree representation of the source code’s syntax. Nodes correspond to language constructs: function definitions, if statements, loops, expressions. Two ASTs can be compared structurally using tree edit distance or, more practically, by serializing the tree into a hash that is invariant under identifier renames but sensitive to control flow changes.

One common AST fingerprinting technique is to compute a hash for each subtree by hashing the node type and the recursive hashes of its children. For example, a function_declaration node that contains an if node with a binary_operator (e.g., ==) will produce a deterministic hash regardless of the actual variable names used in the condition. Two functions with the same control flow graph will have identical AST fingerprints, even if every variable and function name has been changed.

Key insight: AST-based fingerprinting catches code that was rewritten with new identifiers but preserved the original branching and loop logic — the hallmark of a developer who understands the algorithm but tries to hide its source.

Of course, AST comparison is more expensive than token winnowing. A 100,000-line codebase can be tokenized and fingerprinted in seconds. An AST parse for every file plus tree comparison can take minutes. In practice, compliance pipelines use a two-stage approach: token fingerprints for broad screening, then AST comparison on the shortlisted candidates for confirmation.

Real-World Case Study: VMware v. Christoph Hellwig

The VMware case is Exhibit A for why automated license compliance scanning matters. Christoph Hellwig, a Linux kernel developer, discovered that VMware’s proprietary ESXi hypervisor contained code derived from Linux kernel headers and device drivers. VMware did not use any GPL license headers in its code — they had stripped all SPDX identifiers. The code had been heavily modified: variable names were changed, functions were merged, and files were reorganized.

Hellwig’s team used manual code comparison to identify the copies, but they also relied on the fact that the data structures (e.g., page, kmem_cache) retained the same layout of fields. In GPL code, the binary interface between functions is driven by struct definitions — if you change the struct layout, the driver won’t work. So VMware could rename the struct from kmem_cache to VMKCache, but it still had to contain the identical fields in the identical order. Those field-level similarities are exactly what token-based and AST-based fingerprints capture.

In the end, the evidence included hundreds of matching code fingerprints. VMware settled. The case set a precedent that structural copying of GPL code, even after heavy refactoring, constitutes a license violation.

This is not an isolated incident. The Codequiry platform processes thousands of student and enterprise submissions every semester. Its code similarity engine — built on token winnowing and AST hashing — regularly identifies GPL-licensed code from GitHub that has been copied into proprietary assignments or enterprise applications. The same detection logic that catches student plagiarism catches license violations.

Limitations and False Positives

No detection method is perfect. Token-based fingerprinting can produce false positives when two independent developers implement a trivial algorithm (e.g., a Fibonacci sequence, a quicksort partition) in exactly the same way. In such cases, the structural fingerprint of 5–10 tokens may match purely by coincidence. To avoid crying wolf, compliance scanners must require a minimum match length — say, at least 50 matching hashes before flagging a file.

Another source of false positives is common boilerplate: error-handling macros, header guards, standard library includes. These are often identical across projects regardless of license. A well-tuned scanner excludes common code patterns by maintaining a whitelist of known generic fragments.

False negatives are just as dangerous. A sophisticated violator might rewrite the code at the algorithmic level — translating a C function into idiomatic C++ with templates, or reimplementing the kernel logic in a different calling convention. In those cases, even AST hashing may fail because the tree structure itself changes. The only reliable signal left is semantic similarity — for example, comparing call graphs or memory-access patterns. That is still an active research area.

Finally, license compliance scanners must handle multi-license codebases. A single file might contain GPL-licensed code from one source and MIT-licensed code from another. The scanner should attribute each matching section to its upstream license, not just flag the whole file. This requires per-snippet fingerprint matching rather than file-level comparison.

Building a Compliance Pipeline

For enterprises managing a large codebase, manual license review is impossible at scale. A pipeline that integrates with CI/CD tools (GitHub Actions, GitLab CI, Jenkins) can run after every commit. Here’s a typical workflow:

  1. Ingest all source code files, stripping generated code, third-party libraries in designated /vendor or /external directories.
  2. Tokenize and fingerprint each file using winnowing with k=5, w=10. Store hashes in a database.
  3. Match against a curated repository of known open-source code (e.g., the Linux kernel, BusyBox, libcurl, FFmpeg). This repository must be fingerprinted in advance.
  4. Score each match: number of matching hashes, percentage of file covered, and whether matches span multiple disconnected segments (indicating possible deliberate partial copying).
  5. Prioritize high-confidence matches (e.g., >50% hash overlap) for human review. Lower-scoring matches are logged for auditing.
  6. AST confirm top candidates to reduce false positives before alerting the legal team.

The output is a compliance report showing which files contain GPL-licensed code, exactly which lines match, and which upstream project they came from. With automated scanning, a company can detect a violation within hours of the first commit rather than years later in court.

Frequently Asked Questions

Can code fingerprinting detect GPL code that has been translated to another language?

Partially. Token-based fingerprints are language-specific — a C function tokenizes differently than its Java translation. AST-based comparison across languages is possible if the languages share similar constructs (e.g., C and C++), but a complete rewrite in a different paradigm (e.g., from C to JavaScript) will likely miss the match. For cross-language copyleft detection, the strongest signal is still manual review of data structure layouts and algorithms.

Does removing comments and license headers eliminate the risk of detection?

No. Code fingerprints ignore comments entirely. They rely on structural tokens (keywords, operators, punctuation) which cannot be removed without breaking the code. Removing headers only prevents plain-text search from finding the license — it has no effect on similarity detection.

How often do false positives occur in practice?

In our experience with Codequiry’s enterprise scans, the false-positive rate for token-based fingerprinting is roughly 2–5% on a well-defined repository of GPL code. With AST confirmation, that drops below 0.5%. The key is tuning the minimum match threshold and maintaining a comprehensive fingerprint database.

Is automated compliance scanning legally admissible in court?

It can be used as evidence of copying, but it rarely stands alone. The fingerprints provide a strong starting point for expert testimony. In the VMware case, fingerprint evidence was used alongside manual comparison. Courts typically accept automated similarity analysis (like that in plagiarism cases), but each jurisdiction varies. Best practice is to treat the scanner as a discovery tool, not as the final arbiter.

License compliance is not a legal problem solved by lawyers alone — it is a technical problem solved by code analysis. The same algorithms that universities trust to catch student plagiarism are now protecting enterprises from multi-million-dollar lawsuits. Whether you are a CTO evaluating a third-party codebase or a professor checking assignments, the fingerprint never lies.