Stored XSS on TeamPasswordManager
TeamPasswordManager is a password manager (surprise!) written by a single developer, Ferran Barba. You can read more about it here.
An XSS vulnerability exists in TeamPasswordManager <= 12.162.284 that could allow a remote attacker to execute arbitrary JavaScript in the web browser of a user, by including a malicious payload into the ‘name’ parameter when creating a new password in the “My Passwords” page.
To fix the vulnerability, simply update your version of TeamPasswordManager.
This is the story of how CVE-2025-26091 was discovered during an internal pentest.
Welcome to TeamPasswordManager
Let’s start by taking a look at the application.
It’s a pretty standard password manager and most inputs were protected against XSS. Below is an example of some attempts, and how the application properly encodes special characters.
There was one interesting behavior when adding a personal password. For now, let’s just take a look at how a user would add a password to their personal password list.
You start by pressing “New Password”.
You fill in the form… Let’s ignore the notes thing for now :)
The password is added to your passwords. Once again, the payload seems to be properly encoded!
The odd one out
If you take anything from this post, here’s what it should be: just because most fields are properly sanitized, do not assume all of them are.
When going to the “Notes” tab, the special characters in the title are not properly encoded anymore. The XSS still doesn’t trigger because browsers will only expect plain text inside the <title> tags.
So the payload requires a small tweak! Note sorry how this new payload closes the <title> tag first.
If we look at the response, it’s exactly what you’re expecting.
And now for the bad news… This is only a self-XSS. Remember how this only happens when adding passwords to “My Passwords”? :(
Possible escalation scenarios
Either way, let’s explore some scenarios that could turn this self-XSS into something more dangerous. One is easy, CSRF!
Well, not really. A session-based CSRF token is provided, and this is checked when creating the password with the payload. With access to the source code, you could try figuring out how the token is generated and forge one yourself. This would only work if the token isn’t cryptographically secure (aka random, not guessable nor predicatable).
This one requires some creativity, but with a bit of social engineering this could work. There is an import/export feature. You can export your “My Passwords”, send the file to someone else and have them import the file.
Luckily, there isn’t any kind of validation of the file contents when doing the import or export operations. Below is how you would export a .csv with your passwords, and what the file looks like
Timeline
24th Jan 2025: Reported the vulnerability internally and forwarded it to the vendor
27th Jan 2025: Vulnerability was fixed and a patch was released
27th Jan 2025: Requested CVE ID from MITRE
27th Feb 2025: MITRE replies with a CVE ID I can use
24th Jan 2025: Wrote this post and requested CVE to be published
4th Mar 2025: CVE published