Security of Julia, since possible to change the compiler at runtime

Continuing the discussion from This month in Julia World - 2026-08:

Slide 48

Not too surprising. If you have access to the compiler (or infrastructure), then you can change the generated code:

We can already change the parser at runtime. I believe we can also change the compiler in arbitrary ways. E.g. a package could?

Is there any way around this in Julia or languages like Lisp? Even Python? Can and should the compiler be code that is is a separate process? An .so/.dll? could you still unload it and load a new one from the REPL?

Hmmm. As soon as you load a package, its __init__() function runs, which can run arbitrary code, right? So a malicious package can just run malicious code in __init__() - no need to change the compiler.

Precompilation can also run arbitrary code even if it’s not cacheable, not nearly as restricted as typical AOT compile-time computation.

Not generally feasible to send all the information about the current process over to another one, and the new process can be hacked anyway. Precompilation does this, but only by reusing identifiable caches.

I was under the impression the compiler backend couldn’t be swapped out without lower-level injection, but not sure about the frontend. I too would like to know if it’s possible for the default parser+compiler to be ruined at runtime.

That wouldn’t actually be unusual because we can already break the runtime with very little type piracy. Julia can be written in Julia very deep down, and there’s very rarely any deterrence of new world ages. For comparison, I can straightforwardly redefine Float64 addition, changing backspacing in an empty REPL line as a side effect:

julia> Base.:+(x::Float64, y::Float64) = (println("hi"); Base.add_float(x, y))

julia> 1.2 + 3.4
hi
4.6

julia> hi
julia> hi

but I run into a frozen class feature when trying a similar thing in Python:

>>> def blah(self, x): pass # not going to bother with a hack
...
>>> float.__add__ = blah
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    float.__add__ = blah
    ^^^^^^^^^^^^^
TypeError: cannot set '__add__' attribute of immutable type 'float'

A higher reliance on compiled C also protect lower-level implementations. Still, any dynamic language implementing itself on any level is vulnerable to really bad monkey patching:

>>> import builtins
>>> oldabs = builtins.abs
>>> def newabs(x): return -oldabs(x)
...
>>> builtins.abs = newabs
>>> abs(1.2), abs(-3.4)
(-1.2, -3.4)

In conclusion, there’s a lot more to worry about than the parser and compiler, and executing malware is going to hurt regardless.

If you can execute some code to change the compiler, you could just as easily execute malware directly. Vulnerabilities don’t live in a vacuum; they break through some trust barrier.

So, yes, it’s very much a huge problem if an attacker can swap out and compromise the things we sign and distribute. That’s breaking a trust barrier: you trust julialang.org (and juliaup) to serve a good julia! It’s not a vulnerability, however, that you can change the juliaup config to point to a bad bucket elsewhere on the internet that serves some compromised malware. Don’t download and run things you don’t trust!

Similarly, it’s very much a huge problem if an attacker can use an HTTP connection with a HTTP.jl server to unexpectedly make +(::Float64, ::Float64) in that Julia session run rm -rf ~ instead. That’s breaking a trust boundary! But it’s not a vulnerability that you can shoot yourself in the foot in the same manner at a REPL.