12/8/2025
Postmortem: Remote Code Execution on server through Next.js
Unfortunately, and a bit foolishly, my server was attacked Desember 4th 04:32 through a Remote Code Execution (RCE) on a Next.js website. The attack was not noticed until around 19:00 the same day, when I randomly checked Grafana and noticed high CPU usage (See picture below). I have been working on my pre-project for my master's thesis this semester so I have been running a lot of computational heavy workload on the server recently, however I could not remember doing something recently. Since I also share this server with a friend, I thought it was maybe not my activity aswell. However I had some doubt in this, and I also had gut feeling that I had been a bit naive about a recent critical CVE in React Server Components that came out. Fearing the worst, I opened my laptop, and I knew immediately that it was neferious behaviour.

Background
Before I start telling about what happened. I will start off with: yes, it was because of the recent react CVE [0]. I actually knew about this CVE prior to the RCE . Firstly I had gotten a mail from Vercel warning me about the CVE. I quickly went through it, but did not take it to seriously at first. As it was the last weeks in the semester, I was both busy with exams and submission of my project. I therefore have had my head filled with stuff, enough for me to not concern about this. It was not until a friend sent a message on Discord about the CVE that I finally took action.
Incident summary and assessment
I went through all the websites on the server, and noticed that I had two websites that I develop on my own that was susceptable to the vulnerability. I updated packages for the affected websites, and let it go through the workflows on Forgejo for deployment of the website, and called it a day. Unfortunately, one of the pipelines had failed on a staging environment, which went unnoticed.
Fast forward back to when I notice the attack: The attacker had used RCE to download a cryptominer that was hogging the CPU. I had found out it was a from an user running a Next.js app, and I immediately shut it down. I sent a message to my friend and just say (translated to english): "Ayo, someone download a cryptominer on Cassini". I ofcourse also tell him the reason and we started investigating.
First of all I look into the project folder and saw three scripts. Noticing that there are multiple scripts with the same name was a possible warning for multiple exploitations.
-rw-r--r-- 1 alle nogroup 1615 Dec 5 04:32 sex.sh
-rw-r--r-- 1 alle nogroup 1619 Dec 5 11:19 sex.sh.1
-rw-r--r-- 1 alle nogroup 1619 Dec 5 11:19 sex.sh.2
The scripts were very basic. They downloaded a cryptominer and executed it, and it also checked if it had root access and tried to add a systemd service if it was successful. Fortunately the user running the website was a very limited system user, so the possible attacksurface was low.
This was the next.js logs when the first attack was done.
des. 05 04:32:53 cassini npm[3015647]: HTTP request sent, awaiting response... 200 OK
des. 05 04:32:53 cassini npm[3015647]: Length: 1615 (1.6K) [application/x-sh]
des. 05 04:32:53 cassini npm[3015647]: Saving to: ‘sex.sh’
des. 05 04:32:53 cassini npm[3015647]: 0K . 100% 46.3M=0s
des. 05 04:32:53 cassini npm[3015647]: 2025-12-05 04:32:53 (46.3 MB/s) - ‘sex.sh’ saved [1615/1615]
des. 05 04:32:53 cassini npm[3015647]: % Total % Received % Xferd Average Speed Time Time Time Current
des. 05 04:32:53 cassini npm[3015647]: Dload Upload Total Spent Left Speed
Luckily I had actually been exploring file security when using docker, locking down things that should not be globally visible (I was actually gonna write about it on my blog). However I had not finished going through all files, and there were still some API keys and secrets that could have been compromised.
In addition the user had ssh permission that was needed for deployment through automation. Looking into the authorized keys there was another found pubkey in the authorized keys that I did not remember adding. In addition there was an open ssh connection signifiying that the attacker was still in the system. Auditd showed that someone had sshed into the system as that user and also killed the cryptominers that were running around 30 minutes after the first breach, possibly trying to find something else to exploit. I immediately deleted the authorized key and killed the active ssh connection.
alle 266571 266540 0 05:12 ? 00:00:00 sshd-session: alle@pts/0
The safest now would have probably be to reinstall the server from a previous backup. However, as this was a limited system user I instead first checked all the files that had been modified or created the last week that was writable by the compromised user.
find / -type f -writable \( -mtime -7 -o -ctime -7 \)
Filtering out the directory of the web application and pseudo files such
as /proc and /sys, these files were the ones to have potential malicious
content:
/home/alle/.bash_history
/home/alle/.ssh/known_hosts
/home/alle/.ssh/id_ed25519
/home/alle/.ssh/authorized_keys
/home/alle/.ssh/id_ed25519.pub
/home/alle/.lesshst
/home/alle/.viminfo
Because of the attack area, the potential compromised files were examined or deleted (including the web application data). In addition keys any secret that could have been compromised were regenerated.
These are also some tasks done as immediate actions:
- SSH was turned off for system user outside the local network as that is not needed.
- The root password was also changed as it had a weak password and
/etc/shadowhad been compromised.
Learnings and points for improvements
There were clearly some changes i needed to make. This mistake was mostly due to naivety, and could easily have been avoided, if proper precautions were taken. However it has been a good learning point for how fast threat actors will take advantage of exploits in software (in this case only a few days), and how important having patched and up to date software is.
Due to this incident there are some points I would like to focus on and do to improve security and detection on my deployments.
I need proper detection of neferious actions. Especially auditing is needed to notify suspicious activity. I have installed auditd but not configured it that much as I got into other things. Although proper notification of neferious intent is difficult, atleast having strict logging for system user and attempts to privilege escalation is a good start.
In addition I want to make changes to have websites that does not need to be publicly available put behind VPN as having less attack surface area is easier to manage. An other option could be to put it behind apache basic-auth to put a wall between the service and the outside wall.
All in all I think I was pretty lucky with the conequences of what happened. The attack has also straightened me up in regards of security, and made me conscious of good security, which is a good learning point to come out with this.