fix(msteams): prevent auth header leakage on redirect fallback#25045
fix(msteams): prevent auth header leakage on redirect fallback#25045steipete merged 5 commits intoopenclaw:mainfrom
Conversation
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: extensions/msteams/src/attachments/graph.ts
Line: 285-293
Comment:
missing `authorizationAllowHosts` parameter - the `Authorization` header will be forwarded to any redirect target in `allowHosts`, even if outside the auth trust boundary
```suggestion
return await safeFetch({
url: requestUrl,
allowHosts,
authorizationAllowHosts: params.authAllowHosts,
fetchFn,
requestInit: {
...init,
headers,
},
});
```
How can I resolve this? If you propose a fix, please make it concise. |
|
Addressed and now covered by regression test in a07cd38.
|
nikolasdehor
left a comment
There was a problem hiding this comment.
Critical credential leak fix. The issue: when MS Teams fetches attachments from Graph API, the response can be a 302 redirect to an Azure CDN or SharePoint URL. Before this fix, the Authorization header (containing the Graph API bearer token) was forwarded blindly to the redirect target, even if it was outside the auth-trusted domain set.
What I verified:
-
safeFetchinshared.ts: The core fix. A new optionalauthorizationAllowHostsparameter controls which redirect targets are allowed to receive the Authorization header. On each redirect hop, if the target host isn't inauthorizationAllowHosts, the header is deleted fromcurrentHeaders. Key detail: headers are now managed via anew Headers()instance that's passed on each iteration, rather than using the originalrequestInit.headers— this prevents mutation of the caller's headers object while allowing progressive stripping. -
Redirect chain handling: The check runs on every hop (inside the
forloop), not just the first redirect. This is important because a redirect chain likegraph.microsoft.com → cdn.example.com → attacker.comwould strip auth at the cdn hop and keep it stripped. -
One-way stripping: Once Authorization is deleted, it stays deleted for all subsequent hops. This is correct —
currentHeaders.delete("authorization")mutates the Headers object that's reused across iterations. -
download.tsandgraph.ts: BothfetchWithAuthFallbackanddownloadMSTeamsGraphMedianow passauthorizationAllowHoststhrough tosafeFetch. The naming is consistent (authAllowHostsat the caller level,authorizationAllowHostsat thesafeFetchlevel). -
Test coverage: Two tests — one for the attachment download path (redirect from Graph to
attacker.azureedge.net) and one for the SharePoint Graph media path. Both verify that the redirected request has an empty auth header via theseenarray pattern. -
Backward compatibility:
authorizationAllowHostsis optional. When not set, the existing behavior is preserved (no stripping). This means callers that don't use auth don't need changes.
Well-designed fix with clean separation between host allowlisting (can fetch) and auth allowlisting (can send credentials). LGTM.
|
Addressed the Greptile note from #25045 (comment). Fixed in commit That keeps |
|
Addressed Greptile note: Already implemented in commit
|
73a3f31 to
0feadfc
Compare
|
Landed via temp rebase onto main.
Thanks @bmendonca3! |
Summary
This fixes a credential-leak path in MSTeams attachment downloads: when auth fallback is used,
safeFetch()followed redirects with the sameAuthorizationheader, even if the redirect target was outsideauthAllowHosts(but still inside broaderallowHosts).Concretely:
safeFetch()now acceptsauthorizationAllowHostsand stripsAuthorizationbefore redirect hops that are not auth-allowlisted.authAllowHostsintosafeFetch()so redirect forwarding of bearer tokens stays bound to the auth trust boundary.authAllowHosts.Why this matters
An attacker who can influence redirect behavior on an allowlisted media host can exfiltrate Graph bearer tokens to another allowlisted host (for example CDN domain) that is intentionally not auth-trusted. That breaks the intended auth-host boundary and can enable cross-resource data access under stolen token scopes.
Deterministic Reproduction
Validate on this PR branch (fixed behavior)
pnpm install pnpm vitest run --config vitest.extensions.config.ts extensions/msteams/src/attachments.test.ts -t "does not forward Authorization to redirects outside auth allowlist"Expected: test passes and asserts redirected request to
https://attacker.azureedge.net/collecthas emptyAuthorization.Confirm the bug on parent commit (vulnerable behavior)
git checkout f2bdf0ecb^ pnpm vitest run --config vitest.extensions.config.ts extensions/msteams/src/attachments.test.ts -t "does not forward Authorization to redirects outside auth allowlist" git checkout bm/msteams-auth-header-redirect-scopeExpected on parent: test fails because redirected request receives
Authorization.Scope/Trust Alignment (quoted)
From
SECURITY.md:Alignment: this report is a concrete auth-boundary bypass in channel attachment handling (
authAllowHostsvs redirect flow), with deterministic repro and direct demonstrated impact. It is not a prompt-injection-only or shared-operator trust-model claim.Dedupe Check Evidence
Searched open PRs/issues for overlap (2026-02-24 UTC) and found no matching open work for this exact vulnerability:
Reviewed currently open MSTeams-related PRs and none address auth-header redirect leakage in attachment download fallback:
Tests
Greptile Summary
This PR fixes a credential leak vulnerability in MSTeams attachment downloads where
Authorizationheaders were forwarded to redirect targets outside the auth trust boundary (authAllowHosts), even though those targets were within the broaderallowHosts.The fix introduces an
authorizationAllowHostsparameter tosafeFetch()that controls whenAuthorizationheaders are preserved across redirects. When a redirect points to a host outsideauthAllowHosts, the header is stripped before following the redirect. The fix is applied to the auth fallback path indownloadWithAuthFallback()which now passesauthAllowHoststosafeFetch().A comprehensive regression test verifies that redirects to hosts outside the auth allowlist (e.g.,
attacker.azureedge.net) do not receive the bearer token, while the download still succeeds.Confidence Score: 3/5
safeFetch()andfetchWithAuthFallback()is well-designed with proper header stripping logic and comprehensive test coverage. However, the SharePoint download path ingraph.ts:285sets anAuthorizationheader but doesn't passauthorizationAllowHoststosafeFetch(), which means it's still vulnerable to the same credential leak on redirects. This incomplete fix reduces confidence to 3.Last reviewed commit: f2bdf0e