cloudflare / cloudflare/cloudflare-os
Google Gatekeeper falls through unsupported URLs to Gmail
- Dominant language
- TypeScript
- Stars
- 9.9k
- Forks
- 1.2k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 107
Description
## Summary
The Google Gatekeeper treats every URL that does not match its Docs, Sheets, Calendar, or BigQuery branches as a Gmail resource. Unsupported hosts and unsupported paths therefore receive a Gmail capability instead of being rejected.
## Evidence
`packages/gatekeeper-google/src/google.ts:832-955` checks the recognized resource branches, then falls through to `// Default: Gmail` and returns `GMAIL_RESOURCE` without checking `parsed.hostname`, protocol, or whether the URL matches the Gmail resource pattern (`https://mail.google.com/*`).
The capability boundary does not independently reject the mismatch. `packages/workshop-backend/src/overseer.ts:7447-7458` passes the caller-supplied `resourceUrl` to `UserDurableObject.getGatekeeperClassFor()` and stores that original URL in `GatekeeperCreationSpec`. `packages/workshop-backend/src/user.ts:1621-1645` trusts the Gatekeeper-returned resource metadata for policy checks and returns it without comparing it to the requested URL.
## Reproduction from the current source
For a connected Google account, request a Gatekeeper with either of these resource URLs:
```text
https://evil.example/resource
https://docs.google.com/document/not-a-document-id
```
`GatekeeperUserImpl.getGatekeeperClassFor()` falls through to the Gmail branch and returns `GmailGatekeeperImpl` plus `GMAIL_RESOURCE`, even though neither URL is a Gmail URL. A direct client, blueprint, or any caller that reaches `OverseerClientInterface.newGatekeeper()` can supply the URL; the core stores the mismatched original URL as the binding's resource URL.
## Impact
This is not a cross-user account escalation: the capability still comes from the caller's own connected Google account. It is a resource-URL validation and audit-integrity bug. A non-Gmail request silently becomes a Gmail mailbox capability, and the returned resource metadata no longer describes the URL the caller requested. That weakens the intended resource-pattern boundary and can make admin/resource policy and audit records misleading.
The agent request path normally pre-validates URLs using `resolveRequestedResource()`, but the capability boundary is also reached by the frontend and blueprint instantiation paths, so the Gatekeeper should reject unsupported URLs itself rather than rely on callers.
## Suggested direction
Reject unsupported Google hosts and paths before the Gmail fallback, or make each resource parser explicitly recognize its canonical host/pattern and return an error otherwise. Add a regression test that calls `getGatekeeperClassFor()` with a non-Google URL and an unsupported Google path and asserts rejection.
I am filing this as an issue rather than a PR because the repository's `CONTRIBUTING.md` asks external contributors to report bugs and avoid design-level patches.
Contributor guide
Research direction
Start in packages/gatekeeper-google/src/google.ts:832-955, then read the resource flow in packages/workshop-backend/src/overseer.ts:7447-7458 and packages/workshop-backend/src/user.ts:1621-1645. Add regression coverage for a non-Google URL and an unsupported Google path passed to getGatekeeperClassFor(); done means both are rejected instead of receiving GmailGatekeeperImpl or GMAIL_RESOURCE.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100