browsers.fail
← firefox

bugzilla #2088447

Graph cross-origin continuation URLs receive the account OAuth bearer token

firefox low other RESOLVED / DUPLICATE

description

## Summary

Thunderbird's Microsoft Graph delta synchronization accepts the complete URL from a server-supplied `@odata.nextLink`, creates a new request to that URL, and attaches the configured account's OAuth access token without checking that the request has the same origin as the Graph endpoint.

A Graph response can therefore direct Thunderbird to another HTTPS origin and disclose `Authorization: Bearer ...`. The same code is used for message, folder, and calendar delta synchronization. Persisted `@odata.deltaLink` URLs need the same validation before a later authenticated sync.

## Impact

Graph access tokens can carry mailbox read/write and send scopes. A destination that receives the token can reuse it against the resource server until expiration, subject to the granted scopes.

Suggested severity: High (at minimum Moderate). Suggested CVSS 3.1: 8.1 (`AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N`). Suggested CWE: CWE-200/CWE-522 and CWE-918.

## Affected code

- `rust/ms_graph_tb/src/pagination.rs:163-173,193-197` accepts the complete next-link URI and builds a GET from it.
- `rust/graph_xpcom/src/client/sync_messages_for_folder.rs:167-171`
- `rust/graph_xpcom/src/client/sync_folder_hierarchy.rs:112-115`
- `rust/graph_xpcom/src/client/sync_calendar_items.rs:103-107`
- `rust/protocol_shared/src/operation_sender/send_request.rs:56-89,135-149` attaches the OAuth token after checking only HTTPS/loopback, not configured-origin equality.

This is a new authenticated request, not an HTTP redirect, so redirect-layer stripping does not protect it.

## Reproduction

The attached local-only xpcshell PoC starts two loopback servers on different ports. The configured Graph origin returns an empty delta page whose `@odata.nextLink` points to the second origin. The second origin records the request and returns a terminating page.

Verified on Thunderbird Daily 161.0a1, BuildID `20261103100812`, and current comm-central `1e798c885fd5fddbad1da12c73a589b8b8a04f60`:

```text
originsDiffer=true
accountRequests=1
captureRequests=1
accountAuthorization=Bearer access_token
capturedAuthorization=Bearer access_token
exactBearerCopied=true
completed=true
operationErrors=0
Passed: 1
Failed: 0
```

Loopback HTTP is explicitly permitted by the current token transport check, allowing the test to stay offline. The same sender accepts any HTTPS continuation URL. The token is synthetic; the PoC contacts no Microsoft or third-party service.

## Related report

Bug 2083220 covers a repeated **same-origin** `@odata.nextLink` causing an unbounded loop. This report needs only one cross-origin link and demonstrates token disclosure. A visited-link or page-count guard does not fix this trust-boundary issue.

## Recommended fix

Validate and canonicalize both `nextLink` and `deltaLink` before obtaining credentials or sending a request. Require HTTPS and exact origin equality with the configured Graph base URL; reject cross-origin values rather than following them without credentials. Add cross-host, cross-port, downgrade, and stored-delta-link regression tests for all three sync paths.

AI assistance was used for source review and drafting; the attached proof and observations were executed locally with synthetic data.

Attachment SHA-256: `137657E890E23EAF4EFA4ADB07C89BD86BE3E03E0D3795E293878689F44404A8`.