Summary
An authenticated user with read access to Activity could influence the ORDER BY clause of the activity list endpoints by supplying an arbitrary sort column:
GET /api/v1/fleet/activities (ListActivities)
GET /api/v1/fleet/hosts/{id}/activities (ListHostPastActivities)
This originated from the deprecated cursor-pagination helper (appendListOptionsWithCursorToSQL), which interpolated the caller-supplied order key into SQL without an allowlist. The original report's node_key extraction scenario (/api/v1/fleet/labels/{id}/hosts) was remediated separately in #44385; these two activity endpoints were the residual call sites, neither of which joins the hosts table, so node_key was never reachable through them.
Impact
Read-only. Because the order key was interpolated, an authenticated user with Activity read could sort by columns not otherwise returned in these responses. The exposure was bounded to columns on activity_past (e.g. details on /api/v1/fleet/activities, which is not in that endpoint's SELECT; host-only activities are already excluded by WHERE host_only = false). There is no privilege escalation, write access, or reachability of node_key or other host-join columns through these endpoints.
Remediation
The deprecated helper was removed from the codebase. Both endpoints now pass the caller-supplied sort column through SanitizeColumn, which strips all characters except [\w-.] and backtick-quotes each identifier segment. This closes the injection vector: separators, whitespace, parentheses, and quotes cannot survive sanitization, so an expression-based ORDER BY oracle is not constructable.
Affected versions
< fleet-v4.89.0. Fixed in fleet-v4.89.0.
Credit
Thanks to @axel-corsiez for the report.
References
Summary
An authenticated user with read access to Activity could influence the
ORDER BYclause of the activity list endpoints by supplying an arbitrary sort column:GET /api/v1/fleet/activities(ListActivities)GET /api/v1/fleet/hosts/{id}/activities(ListHostPastActivities)This originated from the deprecated cursor-pagination helper (
appendListOptionsWithCursorToSQL), which interpolated the caller-supplied order key into SQL without an allowlist. The original report'snode_keyextraction scenario (/api/v1/fleet/labels/{id}/hosts) was remediated separately in #44385; these two activity endpoints were the residual call sites, neither of which joins thehoststable, sonode_keywas never reachable through them.Impact
Read-only. Because the order key was interpolated, an authenticated user with Activity read could sort by columns not otherwise returned in these responses. The exposure was bounded to columns on
activity_past(e.g.detailson/api/v1/fleet/activities, which is not in that endpoint's SELECT; host-only activities are already excluded byWHERE host_only = false). There is no privilege escalation, write access, or reachability ofnode_keyor other host-join columns through these endpoints.Remediation
The deprecated helper was removed from the codebase. Both endpoints now pass the caller-supplied sort column through
SanitizeColumn, which strips all characters except[\w-.]and backtick-quotes each identifier segment. This closes the injection vector: separators, whitespace, parentheses, and quotes cannot survive sanitization, so an expression-basedORDER BYoracle is not constructable.Affected versions
< fleet-v4.89.0. Fixed infleet-v4.89.0.Credit
Thanks to @axel-corsiez for the report.
References