Personal Access Token scopes aren't honoured by GraphQL subscriptions
Problem
Any personal access token (no matter what scopes are selected) allow you to subscribe to anything in GraphQL regardless of whether or not the scope matches.
This does not grant you access to resources your user cannot access. But it does expand the access of PATs that are meant to be scoped down to less data (eg. read_user
).
Specifically from our testing you can create a PAT with scope read_user
and subscribe to updates for deleting notes on an issue (eg. workItemNoteDeleted
)
How to reproduce
There are some scripts in https://gitlab.com/DylanGriffith/graphql-susbcription-client which is pending being moved to another home. It's private as we don't want to draw attention to this until it is fixed. You can ask for access or you can follow the steps below to set this up:
Here is some node code for subscribing to the API:
// cable.js
import WebSocket from 'ws'
import { createCable } from '@anycable/core'
export default createCable('ws://127.0.0.1:3000/-/cable', {
websocketImplementation: WebSocket,
websocketOptions: { headers: { 'Authorization': 'Bearer <YOUR_PAT_HERE>' }}
})
// subscribe.js
import cable from './cable.js'
const subscription = cable.subscribeTo('GraphqlChannel', {
"query":"subscription workItemNoteDeleted($noteableId: NoteableID) { workItemNoteDeleted(noteableId: $noteableId) { id discussionId lastDiscussionNote __typename }}","variables":{"noteableId":"gid://gitlab/WorkItem/609"},"operationName":"workItemNoteDeleted","nonce":"619ea684-343a-4060-b458-88cc4ceb028c"
});
//const _ = await subscription.perform('speak', { msg: 'Hello' })
subscription.on('message', msg => {
console.log(msg);
})
- Create these files in a directory
- Run
yarn init
in that directory - Run
yarn add @anycable/core
- You may need to run
yarn add ws
- Update your GitLab instance with
config.action_cable.disable_request_forgery_protection = true
in yourconfig/initializers/action_cable.rb
(or figure out how to pass this request forgery check which probably requires some headers) - Update the above code with a URL for your GitLab instance (can be gitlab.com pending solving request forgery check above)
- Update the above code with a correct
gid://gitlab/WorkItem
for a work item on your instance that you have access to read. You can find this by finding the noteable (e.g. Issue) on the rails console, then finding it's GID withissue.to_global_id.to_s
, and then replaceIssue
in the string withWorkItem
- Update the above code with
<YOUR_PAT_HERE>
with a PAT that hasread_user
scope only - Run the subscription code with
node subscribe.js
- Create a note on your work item
- Delete a note from your work item
- You will see log message showing the deleted note
You shouldn't be able to see anything about notes or work items with a read_user
scoped token.
Introduced by
In this MR we started allowing people to use PATs with graphql subscriptions. Prior to that only cookies worked so there was no such risk.