Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
linux-entra-sso-PoC — PoC — origin validation error enabling Entra ID PRT SSO cookie exfiltration in linux-entra-sso (GHSA-g9vc-5j77-f2cm, CVE-2026-87005, CVSS 5.3). | Kitploit
Tools/GitHubGitHub/squeeze440/linux-entra-sso-poc
Vulnerability AnalysisExploitationWeb Application ExploitationInformation GatheringWeb SecurityPenetration TestingAuthenticationPapers & Research
GitHubsqueeze440/linux-entra-sso-poc

linux-entra-sso-PoC

PoC — origin validation error enabling Entra ID PRT SSO cookie exfiltration in linux-entra-sso (GHSA-g9vc-5j77-f2cm, CVE-2026-87005, CVSS 5.3).

191 month agoNot yet reviewed
View Repository

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Summary

CVE status: requested, pending assignment. This finding is published as GHSA-g9vc-5j77-f2cm. On CVE assignment this repository is renamed CVE-YYYY-NNNNN-linux-entra-sso-PoC and this banner is replaced with the CVE link.

ResearcherDostxodjayev Abdullox (@squeeze440)
AdvisoryGHSA-g9vc-5j77-f2cm
CVSS 3.15.3 (Medium)
WeaknessCWE-346, CWE-20

Summary

Platform.SSO_URL in linux-entra-sso lacks a trailing path separator, so the Firefox/Thunderbird onBeforeSendHeaders guard (e.url.startsWith(Platform.SSO_URL)) is bypassed by any attacker-registered domain of the form login.microsoftonline.com.<attacker-domain>, causing the extension to acquire and inject a live Entra ID Primary Refresh Token (PRT) SSO cookie into requests sent to the attacker's own host.

Product

siemens/linux-entra-sso — Browser plugin for Linux to SSO on Microsoft Entra ID via the local Microsoft Identity Broker (Intune). Firefox build is practically exploitable; Thunderbird shares the identical vulnerable code path but is not currently reachable via this vector (see Details); Chrome/Chromium is not affected (see Details).

Tested Version

v1.10.0 (commit 676854c, current main as of 2026-08-03). Confirmed present in the current release, i.e. not fixed by GHSA-52rj-42vh-2rxc / CVE-2026-42177 (that fix touched only the Chrome declarativeNetRequest adapter).

Estimated CVSS v3.1

5.3 (Medium) — CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N

  • AC:H — exploitation requires the extension to hold a granted host permission that covers the attacker's crafted hostname. In practice the attacker must social-engineer the victim into clicking the extension's "Background SSO (enable)" link while on the attacker's page — a condition outside the attacker's direct control, matching the complexity rationale used for the sibling GHSA-52rj-42vh-2rxc.
  • UI:R — the permission grant is an explicit user click.
  • C:H — a stolen PRT SSO cookie is directly replayable against login.microsoftonline.com to mint access/ID tokens for any app the victim has consented to (full SSO session hijack).
  • I:N/A:N — the bug discloses a credential but does not itself modify data or availability.

Details

Root cause — src/platform.js:9:

static SSO_URL = "https://login.microsoftonline.com";

No trailing /.

Vulnerable check — platform/firefox/js/platform-firefox.js:55-59:

async #onBeforeSendHeaders(e) {
    // filter out requests that are not part of the OAuth2.0 flow
    if (!e.url.startsWith(Platform.SSO_URL)) {
        return { requestHeaders: e.requestHeaders };
    }
    ...

String.prototype.startsWith performs a raw character-prefix comparison, not a hostname/origin comparison. Because Platform.SSO_URL has no trailing separator, any URL whose host is login.microsoftonline.com.<anything> — a syntactically valid DNS name the attacker fully controls — also satisfies the check, e.g.:

"https://login.microsoftonline.com.attacker.example/phish".startsWith("https://login.microsoftonline.com")
=> true

This is the same defensive check that GHSA-52rj-42vh-2rxc's own description called "the canonical defensive check ... absent from the Chrome adapter" — it exists here, but is itself bypassable, so the advisory's fix (which only hardened Chrome's declarativeNetRequest rule) left this path open. platform/thunderbird/js/platform-thunderbird.js extends PlatformFirefox without overriding update_request_handlers() or #onBeforeSendHeaders, so Thunderbird inherits the same flaw.

Trigger path (update_request_handlers, platform/firefox/js/platform-firefox.js:36-53): the listener is registered with urls: this.well_known_app_filters, which is populated from chrome.permissions.getAll().origins (src/platform.js:78-79, update_host_permissions()). Any host permission the user has granted — including a single-site grant via the popup's "Background SSO (enable)" link (popup/menu.js:171-260, using current_filter = "https://" + tab_hostname + "/*" derived from the active tab) — is enough to register the listener for that exact host. No catch-all https://*/* permission is required, unlike the exploitation prerequisite described in GHSA-52rj-42vh-2rxc; a single targeted grant on the attacker's own look-alike domain is sufficient here, which is a lower bar than the prior advisory's PoC.

Sink — same file, lines 60-70:

let prt = await this.#broker.acquirePrtSsoCookie(this.account, e.url);
ssoLog("inject PRT SSO into request headers");
e.requestHeaders.push({ name: prt.cookieName, value: prt.cookieContent });

e.url (the full attacker URL) is passed straight through as ssoUrl to the native broker. linux-entra-sso.py:27-30 documents that the Microsoft broker backend does not validate ssoUrl server-side ("the correct value is not checked ... by the authorization backend"), so a cookie is issued regardless, and it is injected into headers on the request actually going to the attacker's own host — a direct exfiltration, not merely a header set on a Microsoft-bound request.

Chrome is not affected: platform/chrome/js/platform-chrome.js:96-99 (post GHSA-52rj-42vh-2rxc fix, commit 8183759) anchors with "|" + Platform.SSO_URL + "/" (start-of-string anchor + trailing slash) and adds an explicit requestDomains: [URL.parse(Platform.SSO_URL).hostname] allow-list — both of which correctly reject a login.microsoftonline.com.attacker.example host.

Thunderbird — same vulnerable code, not currently reachable via this vector: platform/thunderbird/js/platform-thunderbird.js extends PlatformFirefox unchanged, so the identical startsWith bypass exists in the Thunderbird build's binary. However platform/thunderbird/manifest.json declares only a fixed "host_permissions": ["https://login.microsoftonline.com/*"] with no optional_host_permissions key. WebExtensions only allows chrome.permissions.request() to grant origins that are pre-declared in optional_permissions/optional_host_permissions; since Thunderbird declares none, the popup's "Background SSO (enable)" flow (popup/menu.js:259-261) cannot obtain permission for an attacker-chosen domain on Thunderbird today. The bug is latent there, not currently attacker-reachable, and should still be fixed for defense-in-depth / in case optional_host_permissions is ever added to that manifest.

Proof of Concept

Dynamically confirmed the vulnerable predicate against the real shipped constant (imported directly from the target's src/platform.js, not hand-copied). Script kept at ~/engagements/linux-entra-sso/evidence/prt_bypass_poc.mjs.

$ node prt_bypass_poc.mjs
Real Platform.SSO_URL from src/platform.js: "https://login.microsoftonline.com"

Legit MS URL passes filter (expected true): true
Attacker domain-suffix URL: https://login.microsoftonline.com.attacker.example/phish
Attacker URL passes filter (SHOULD be false, is): true

[CONFIRMED] Platform.SSO_URL lacks a trailing '/', so startsWith()
treats 'login.microsoftonline.com.attacker.example' as an in-scope
SSO endpoint. onBeforeSendHeaders would call:
  broker.acquirePrtSsoCookie(this.account, "https://login.microsoftonline.com.attacker.example/phish")
and inject the returned PRT cookie into the request headers sent to
the attacker-controlled host.
Download Tool