Why Taint Analysis Works Better Backwards

▶ Watch (07:40)

Most taint analysis tools walk forward: source to sink. Ray Kai argues that is the wrong direction. Sinks are easy to enumerate. Start there, trace backward, and you only investigate paths that terminate at a dangerous function. That guarantees the finding has severity worth the work.

“if you approach approach it upside down as sync to source it’s actually much more simpler” — Ray Kai

The forward direction floods you with false positives or low-severity findings. Backward traversal also carries richer context: the sink’s calling code already hints at what data shapes are relevant, which lets the analyzer ignore unrelated conditional branches early.

Tree-of-Thoughts as a Dataflow Engine

▶ Watch (09:26)

Kai connected sink-to-source search to Tree-of-Thoughts after noticing both are pruning problems. In Tree-of-Thoughts, a model votes on which branch to follow, discards dead ends, and rewinds when stuck. Taint traversal works the same way: vote on which predecessor node leads toward a user-controlled source, discard unrelated subgraphs, and backtrack when the path dies.

Tree-of-AST builds a call graph from identified sinks, traverses toward sources using that voting mechanism, then reverses direction to generate constraint tasks for payload construction. No path explosion, because the pruned subgraph is already small.

Building the Internal Program Representation

▶ Watch (14:47)

Sasha Zyuzin handled implementation. The team’s first attempt used raw ASTs, which are language-specific and single-file. Cross-file symbol resolution required topological sorts over imports. That complexity pointed toward Stack Graphs, a GitHub-built framework on Tree-sitter that handles import resolution and symbol disambiguation across languages with a universal query API.

They tried building their own Stack Graphs implementation in Rust, two months before Black Hat. Two people. They failed. A closed-source wrapper library reduced the interface to two function calls but froze on any project over 200 files. Their fix: analyze the 200 files closest to each sink first, then expand outward.

LLM Orchestration and the Design Principles That Follow

▶ Watch (21:25)

The LLM never sees a whole codebase. Tree-of-AST feeds it one code slice at a time: source detection, path selection, backtracking decisions. A second, stronger model re-weights confidence scores to cut false positives. Taint tracking uses parameter-based tainting rather than argument tracking or direct sync tracing, which covers three of the most common vulnerability call patterns and misses fewer cases.

“we actually apply human cognitive process heristics on vulnerability analysis. So we solve the problem in a way as human would” — Sasha Zyuzin

Zyuzin’s closing principle: separate strategic decisions (LLM) from mechanical execution (deterministic code). The tool rediscovered existing CVEs in large Python ML projects. No benchmark dataset covers large codebases with mapped vulnerabilities, so full precision measurement is still open work.

Notable Quotes

if you approach approach it upside down as sync to source it’s actually much more simpler Ray Kai · ▶ 7:47

I submitted 51 reports. Only 18 of them got a CVE. Ray Kai · ▶ 5:37

we actually apply human cognitive process heristics on vulnerability analysis. So we solve the problem in a way as human would Sasha Zyuzin · ▶ 24:54

Key Takeaways

  • Sink-to-source taint traversal guarantees severity and cuts false positives versus forward source-to-sink analysis.
  • Tree-of-Thoughts voting plus look-ahead maps directly onto stateful sync-to-source path search in large codebases.
  • Feeding the LLM one small code slice at a time avoids context overload and the path explosion problem.