Synopsis
Note: Another researcher identified the same vulnerability during the disclosure process with the Nous Researcher team.
In Hermes Agent, the public GET /auth/native/authorize flow validates the redirect_uri with Python's urllib.parse.urlparse, then hands the raw, unnormalized value back to the browser after authentication.
The two parsers treat backslashes differently. Python's parser and the browser's WHATWG parser therefore disagree on the URL's actual host. The server can accept a URL it classifies as loopback (127.0.0.1) while the browser navigates to a different, attacker-controlled origin. The attacker also chooses the PKCE challenge, so they can exchange the leaked authorization code for the victim account's tokens. This results in a full session takeover.
The _validate_loopback_redirect_uri function is explicitly meant to allow only literal loopback addresses, since a remote origin would otherwise receive a live authorization code. However, it parses raw, checks parsed.hostname, and then returns raw unchanged. register_pending stores this raw string. After a valid sign-in, auth_password_login appends code and state to it, and the page script redirects with window.location.assign(data.next).
The discrepancy reproduces with http://127.0.0.1:17777\@127.0.0.1:27777/callback. urlparse reads 127.0.0.1:17777\ as user information before the @ and reports the hostname as 127.0.0.1, with port 27777. The browser instead treats \ as a path separator in an HTTP URL. It opens http://127.0.0.1:17777/@127.0.0.1:27777/callback, so the request goes to the origin on port 17777. In testing, the browser reached this second origin carrying the code and state parameters.
A remote host placed before the backslash would receive the authorization code in the same way.
Solution
Upgrade to Hermes Agent version 0.21.6 or later.
Additional References
https://github.com/NousResearch/hermes-agent/releases/tag/v0.21.6https://github.com/NousResearch/hermes-agent/pull/130685
Disclosure Timeline
All information within TRA advisories is provided “as is”, without warranty of any kind, including the implied warranties of merchantability and fitness for a particular purpose, and with no guarantee of completeness, accuracy, or timeliness. Individuals and organizations are responsible for assessing the impact of any actual or potential security vulnerability.
Tenable takes product security very seriously. If you believe you have found a vulnerability in one of our products, we ask that you please work with us to quickly resolve it in order to protect customers. Tenable believes in responding quickly to such reports, maintaining communication with researchers, and providing a solution in short order.
For more details on submitting vulnerability information, please see our Vulnerability Reporting Guidelines page.
If you have questions or corrections about this advisory, please email [email protected]
Tenable One
Request a demo
The world’s leading AI-powered exposure management platform.
Thank You
Thank you for your interest in Tenable One.
A representative will be in touch soon.
Form ID: 7469
Form Name: one-eval
Form Class: c-form form-panel__global-form c-form--mkto js-mkto-no-css js-form-hanging-label c-form--hide-comments
Form Wrapper ID: one-eval-form-wrapper
Confirmation Class: one-eval-confirmform-modal
Simulate Success