Prelude
Content
In this post, I discuss an account takeover vulnerability that I discovered in the OpenAEV platfom including the background, the discovery process, and the impact.
Introduction
What is OpenAEV (formerly OpenBAS)
Filigran, the organization behind OpenAEV, describes their product with the following sentences "OpenAEV is an open source platform allowing organizations to plan, schedule and conduct cyber adversary simulation campaign and tests. The goal is to create a powerful, reliable and open source tool to effectively plan and play all types of simulations, training and exercises from the technical level to the strategic one."
In short, it is a tool for automated testing of an organization's security posture. It allows organizations to test how ready their systems and personel are for a real cyber attack. It does this by allowing OpenAEV operators (users) to design, implement, and carry out cyber attack scenarios.
How OpenAEV Works
For the purposes of this post, OpenAEV consists of only a few core components: the server, the agent (executor), and the implant (payload). Below is a diagram that shows the relationship between these components with a non-technical analogy at the very bottom.

The implants are payloads that are used to execute malicious commands, collect the outputs, and test the defense's response. They are the foundational building blocks for creating an cyber attack simulation. The implants are executed by the agent which is meant to be excluded from antivirus scans [1.0]. The server enables an OpenAEV operator to control the agent. It does this by hosting a web interface on port 8080, where OpenAEV operators can log in to manage and monitor agents. Through this interface, an operator can determine which payloads an agent runs, when they are executed, and how the resulting output is handled.
For a non-technical explanation, imagine that you made a contract with a household robots firm. They agreed to deliver 5 worker robots and 1 manager robot. The workers take commands from the manager and the manager takes commands from you. Apart from these, the firm said that you'd receive a special phone with which you could talk to the manager and give the robots tasks to complete. In this analogy, the worker robots are the implants, the manager robot is the agent, and the phone is the OpenAEV server that you can use to talk to the manager. And the screen of the phone is the web interface.
[1.0] https://docs.openaev.io/latest/usage/openaev-agent/#installation
Why Find a Vulnerability in OpenAEV?
The Background
Last year, I took a cybersecurity semester at my university. As part of our program, we had to work in a group to develop a project for an external organization. In my case, our client was an IT consultancy company that wanted a cyber attack simulation using OpenAEV. My guess is that they wanted to demonstrate to their clients the effects of having an immature cybersecurity posture (probably with zero cost too). They had come to our university with their project idea, and six dudes including me decided to take it on. That decision is what eventually pushed me to start digging into OpenAEV and hunting for vulnerabilities.
The Drive
The more I learned about OpenAEV the more ideas I had about how an attacker could potentially abuse it. For example, as I mentioned earlier, the OpenAEV agent is installed in a directory that is meant to be excluded from antivirus scans. In some scenarios, this could allow an attacker to drop their own malware into the same folder and evade detection.
Even worse, if an attacker were able to compromise the OpenAEV server, they would gain control over every machine that runs an agent. The impact would be similar to that of getting a C2 server compromised. Or getting the phone that you use to manage your household robots stolen. Depending on where the agents are installed, this could enable privilege escalation or lateral movement, especially if they're running on production systems.
The idea of actually looking at the source code didn't occur to me at first. That changed when a teammate jokingly said, "Why not look for vulnerabilities in OpenAEV?" to which I replied with a casual "Hmm, I'll do that next." completely missing his joking tone.
So, after we wrapped up the project and a few days before the final delivery, I sat down and opened OpenAEV's GitHub page, hoping to find a vulnerability in time to jokingly tell our client "By the way, the version of OpenAEV you're using has a critical vulnerability." I did not do that, of course, mostly because I didn't have the guts but also because they ran OpenAEV in an isolated test environment anyway.
Discovery
Threat Modeling
One of the first things I do before I start looking for vulnerabilities in a system is to identify what others have found so far. In OpenAEV's case, I didn't find many reports regarding authentication even though it's a critical part of OpenAEV as I described the potential impact of having the OpenAEV server compromised earlier. The lack of publicly disclosed authentication vulnerabilities doesn't mean much of course; maybe the authentication is safe, or maybe the developers found the vulnerabilities internally and fixed them already.
One thing that caught my attention during this phase of my research was an LLM prompt which was used for code review [2.0]. It specifically stated that the LLM should review authentication and authorization logic. So I started to wonder "How good of a job did this LLM do?", "Did everyone just trust the LLM to find all the problems?", "Did other researchers avoid authentication and authorization because they saw this prompt?". Regardless, now it was time to look at OpenAEV's authentication functionalities.
Spotting the Vulnerable Code
OpenAEV is a largely custom-made platform. And when it comes to custom-made code, there are 2 quotes that come to mind "Never roll your own crypto" and "Never roll your own auth". I will not debate if these quotes are right or not, but I will say that your interest should go up a bit when you see a custom password reset logic as it contains elements from both auth and crypto.
And a custom password reset logic is exactly what I found when I dove into the unauthenticated routes and looked at the password reset endpoint [2.1].
@PostMapping("/api/reset")
@RBAC(skipRBAC = true)
public ResponseEntity<?> passwordReset(@Valid @RequestBody ResetUserInput input) {
Optional<User> optionalUser = userRepository.findByEmailIgnoreCase(input.getLogin());
if (optionalUser.isPresent()) {
User user = optionalUser.get();
String resetToken = RandomStringUtils.randomNumeric(8);
String username = user.getName() != null ? user.getName() : user.getEmail();
if ("fr".equals(input.getLang())) {
String subject = resetToken + " est votre code de récupération de compte OpenAEV";
String body =
"Bonjour "
+ username
+ ",</br>"
+ "Nous avons reçu une demande de réinitialisation de votre mot de passe OpenAEV.</br>"
+ "Entrez le code de réinitialisation du mot de passe suivant : "
+ resetToken;
mailingService.sendEmail(subject, body, List.of(user));
} else {
String subject = resetToken + " is your recovery code of your OpenAEV account";
String body =
"Hi "
+ username
+ ",</br>"
+ "A request has been made to reset your OpenAEV password.</br>"
+ "Enter the following password recovery code: "
+ resetToken;
mailingService.sendEmail(subject, body, List.of(user));
}
// Store in memory reset token
resetTokenMap.put(resetToken, user.getId());
return ResponseEntity.ok().build();
}
return ResponseEntity.badRequest().build();
}Did you notice all the problems in the code? You can try finding as much as you can if you want to. If you're a non-coder, here's a description of what the code does if you want to hop in on the fun too.
This function runs when a user makes a post request to /api/reset. It doesn't have RBAC (authorization) checks as it's an unauthenticated endpoint. On the first line inside the function, an HTTP POST variable called login is taken from the request body of the HTTP request with the getLogin() function and used as a key to access the User that has the value of login as their email. Later, the code checks if this user exists, If they do exist, an 8 digit password reset token is generated and sent as an e-mail to the address that was provided by the login parameter (e.g. admin@organization.com). After the email is sent, the token is stored on RAM for later use. Now you can try finding the problems.
Let's focus on what matters as far as authentication bypass is concerned. Did you notice how few possible password reset tokens there are? Well, maybe 100,000,000 (10⁸) is not the number that comes to your mind when thinking about small numbers, but this is the first crack in the gates of the castle. The second crack is the lack of any token expiration time. At this point, the findings are already worth reporting. We can create a token and brute-force it until we hit the correct token maybe 5 days or 5 months from now. Also, you can find many valid non-expiring token reports online with very little impact. But in this case, I preferred diving deeper and increasing the impact as much as I could.
This is where we get to the third and the final crack that gives us access to the castle that is the OpenAEV server. The function never invalidates old tokens when new ones are generated. As a result, if an attacker requests a password reset 2,000 times for an admin account whose email address they know, the application ends up holding 2,000 valid password reset tokens in memory. After this point, what was once a 1 in 100,000,000 chance becomes 1 in 50,000 which can be brute-forced using only 100 requests per second within 10 minutes with regular luck. Suddenly, how big does a hundred million really feel?
This technique does not require any email service such as IMAP to be enabled on OpenAEV. However, the lack of an email service makes the attack more stealthy than flooding the target's email box with hundreds of password reset request. But even if an email service is configured, an attacker could initiate the attack at night to avoid suspicion. The only requirement for the attack to work is that the attacker knows the email address of an OpenAEV account. But, this bottleneck was addressed by some of my other reports involving username enumeration (e.g. CVE-2026–24468). Moreover, once an attacker compromises a regular user account, they have the ability to view the email addresses of all the users including admins which leads to admin account takeover and server compromise.
Impact
As I mentioned in the Drive section, compromising an OpenAEV server has an impact similar to that of compromising a Command & Control server [3.0]. An attacker can access the data collected by OpenAEV agents or create new payloads for an OpenAEV agent to execute their malicious commands on "infected" machines. This has devastating impacts if OpenAEV agents are installed on production environments.
If you watched the video referenced in link [3.0] I have a personal opinion to give: If you hack a malicious server or a malware, even though it's an honourable act, isn't publicly disclosing the vulnerability only helping the bad guys [3.1] [3.2]? Even though the vulnerability was patched before your disclosure, they now know people are actively trying to hack their servers which means they are likely to be more careful in their operations. I'm not saying this to throw shade on anyone's work, but to highlight what I think is an important part of responsible disclosure.
[3.0] https://www.youtube.com/watch?v=fMxSRFYXMV0
[3.2] https://www.theregister.com/2022/07/06/hive-ransomware-rust-microsoft/
Conclusion
The vulnerabilities discussed in this post demonstrates how multiple small coding oversights can turn into a big security problem. Companies and individuals must be careful when they are introducing new assets to their systems. A tool for improving your defenses can become the weakest link in the chain. This post once again demonstrates the importance of continuous security tests and code analysis.
The vulnerabilities discussed in this post was patched in version 2.13. The criticial vulnerability received a CVSS 3.1 score of 9.1 and the CVE number CVE-2026–24467 [4.0].
If you're using an version of OpenAEV or OpenBAS that is below 2.13, I urge you to update the software.
And that's it. Hope you gained something out of this post. As always, if you have questions, criticisms, or just want to reach out, you know how to find my contact details.
[4.0] https://github.com/OpenAEV-Platform/openaev/security/advisories/GHSA-vcjx-vw28-25p2
EOF