# Global ID type confusion in mutations

Mutation resolves a global ID without asserting the object's class before acting or checking ability

_Area: Web access control and IDOR. Seen in 2 disclosed reports; 2 confirmed bounties: $4,000 and $5,000; latest 2020-11-02. Updated 2026-10-23._

## How it works
A mutation takes a global ID and resolves it to whatever object that ID points to. The code then runs its action and permission check on the resolved object, not on the type the mutation was written for. The broken assumption: the ID belongs to the expected class. When the resolver skips a type assertion, any object the caller has some ability on can be fed into a service meant for a different, more sensitive object. The ability check keys off the resolved object's own ability name, so a weaker ability on the wrong object passes — e.g. a DiffNote passes `admin_note` and is then handed to the snippet destroy service [E2](https://bugbountylibrary.com/r/h1%3A858671.md).

## Where it shows up
- Mutations calling `object_from_id!` / `authorized_find!` / `find_object` with no class check on the result [E2](https://bugbountylibrary.com/r/h1%3A858671.md)[E4](https://bugbountylibrary.com/r/h1%3A960244.md).
- Ability checks that derive the permission from the resolved object's ability name rather than the mutation's intended type [E2](https://bugbountylibrary.com/r/h1%3A858671.md).
- Delete/destroy services invoked directly on the resolved object [E2](https://bugbountylibrary.com/r/h1%3A858671.md)[E4](https://bugbountylibrary.com/r/h1%3A960244.md).
- Node lookups accepting IDs of any type and passing them downstream.
- Auth interfaces satisfied by multiple principal types where `GetID()` returns an untyped int written straight into an owner/tenant column [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-vvcv-vpph-h844.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-32r8-5843-4qw2.md).

## How to review
For every mutation taking a global ID, trace parse → resolve → assert → ability → service:
1. Resolve the ID.
2. Confirm an explicit class assertion (`is_a?`/type guard) runs before any action or permission check.
3. Confirm the ability check is evaluated against the mutation's declared type, not the resolved object.
4. Confirm the service receives only an instance of the declared type.
Invariant: the object handed to the service must be an instance of the mutation's declared type. Missing type guard and missing authorization are distinct bugs — a guard does not replace an ability check, and vice versa; look for both. For multi-principal auth interfaces, grep every `GetID()`/id comparison for a type guard, especially where a fast-path self-check precedes the only real check [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-32r8-5843-4qw2.md).

## Variants seen
- Maintainer passes a DiffNote GID to `destroySnippet`, deleting the project repository [E2](https://bugbountylibrary.com/r/h1%3A858671.md).
- Developer passes a Project GID to `deleteAnnotation`, deleting the project and repository [E4](https://bugbountylibrary.com/r/h1%3A960244.md).
- Link-share principal ID collides with `users.id`; token handlers write it to `owner_id`, minting tokens for another user [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-vvcv-vpph-h844.md).
- Same collision at team/bot permission sinks enables cross-account team removal and roster disclosure [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-32r8-5843-4qw2.md).

## Impact and severity
High: cross-object deletion of repositories, projects and groups by lower-privileged users [E2](https://bugbountylibrary.com/r/h1%3A858671.md)[E4](https://bugbountylibrary.com/r/h1%3A960244.md), and cross-account token issuance and team removal [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-vvcv-vpph-h844.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-32r8-5843-4qw2.md). Severity rises when the service is destructive and hard to reverse, and when the caller needs only a weak ability on the resolved object.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-vvcv-vpph-h844.md
- E2: https://bugbountylibrary.com/r/h1%3A858671.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-32r8-5843-4qw2.md
- E4: https://bugbountylibrary.com/r/h1%3A960244.md
