Scripting languages are an essential part of many software environments. Common
languages like Python, Ruby, or PHP power large parts of the modern web but bugs
in their runtime environments allow attackers to break memory safety and
sandboxing guarantees. A common bug class is callback bugs which happen when
user-defined callbacks violate runtime invariants. For example, an object may be
freed that is still in active use. These issues result in use-after-free, null
pointer dereferences or type confusion.
Example of clearing a list while iterating through it:
class poc():
def __eq__(self, other):
l.clear()
return NotImplemented
l = [poc(), poc()]
3 in l
The check on the last line triggers a use-after-free as the l.clear()
removed the elements in the array during the equal check. Such interactions
between native implementations and user defined callbacks result in violations
of the language level guarantees.
Triggering a callback bug requires a set of four preconditions that are
satisfied: (i) control flow must reach a callback in the script, (ii) the
callback must involve an attacker-controlled object, (iii) the callback must
introduce unintended side effects such as freeing memory, and (iv) the native
code must be unaware of the memory operation and then mishandles the affected
object after the callback returns.

Our goal in this research is to establish a link between the script-side
callbacks and their native-side invokers and to discover such bugs
automatically. In CrossFit, we combine static analysis (to find interesting
locations and patterns) with targeted fuzzing to trigger these bugs. CrossFit
generates PoC scripts with custom classes and magic methods to demonstrate these
vulnerabilities.
The key idea behind CrossFit is that we leverage context link analysis to bridge
the gap between the script side and the runtime side. As these are different
programming languages and contexts with different guarantees, we have to keep
state at these different levels of abstraction. For each scripting language, we
identify these callback invokers among their public API and then build our
analysis on the LLVM IR level to handle the low level implementations
transparently. Using this collected information, CrossFit then generates
targeted scripts with PoC inputs to test the four conditions of callback bugs.
This allows us to bias the generation towards scripts that are more likely to
trigger interesting bugs.
In our evaluation on PHP, Python, and Ruby we discovered 21 new bugs and
demonstrated that our targeted PoC generation can cover callback code and
cross-language interactions more deeply. The full details are in the
CrossFit paper and the
source code are of course
available.
This work is published at FSE'26 and thhe main credit of this work goes to
Chibin Zhang who worked on the abstractions, refinement of the bug pattern, and
design of the PoC generator.