Developers lean on AI coding assistants for a growing share of their daily work, letting the tools predict the next few lines and accepting many suggestions with a quick glance. Those tools learn from large collections of code, and some of that code can be tampered with before training starts. A poisoned example teaches a model to write insecure code when it sees a certain cue, and the flaw sits quietly until the right prompt sets it off.

backdoored code completions

Most defenses aim to catch this poisoning early, screening training data or scanning outputs for known problems. A team from the University of Louisville and the University of North Texas built a system called CodeTracer for the moment after those defenses let something slip. Their work starts from a model that has already produced a harmful completion. The job is to trace that completion back to the training examples that taught the behavior.

The researchers built the method for a setting that matches how large fine-tuning pipelines run in practice. Gradients from training are gone by the time anyone looks. The people running the check know only the fine-tuning corpus and the report of the bad completion, which includes the prompt and the code the model produced. A question guides the work: “Who planted the bug?”

That order of work lines up with how any security incident gets handled. Root-cause analysis, traceback, and cleanup come after the event. CodeTracer applies the same sequence to a machine learning supply chain, where poisoned data can enter through public repositories and ride into a company’s own model during fine-tuning.

CodeTracer runs in three stages. First it reads the harmful completion and builds a structured summary of the unsafe behavior, stripping away surface details like variable names. Second it searches the training data for code that carries the same underlying logic, narrowing a huge pool of files down to a small candidate set. Third it asks a language model to weigh each candidate against the summary and decide whether it holds the same unsafe pattern.

The default build uses GPT-4.1 for the reading and judging steps and a code encoder called UniXcoder for the search. The narrowing stage keeps the top 500 candidates, a slice small enough to review one at a time.

The evaluation drew on more than a million Python source files pulled from GitHub repositories that each carried at least a hundred stars. A small number of poisoned examples went into that pool for the test.