Loading HuntDB...

Unauthenticated users can obtain information about Checklist objects with unclaimed ChecklistCheck objects

Medium
H
HackerOne
Submitted None
Reported by jobert

Vulnerability Details

Technical details and impact analysis

Improper Access Control - Generic
The `Checklist` objects that can be queried through GraphQL are supposed to only be accessible by program members, the users who claimed or responded to a check belonging to a checklist, and HackerOne Pentesters. The `Checklist` object is also supposed to be in the `running` state (e.g. when the platform collects responses for the checks) for HackerOne Pentesters to access them. The authorization check is implemented as follows: ```ruby class ProtectedChecklist include ::ProtectedAttribute::Protector model { Checklist } copy_roles(ProtectedTeam) do Checklist.joins(:team) end property(:RUNNING_CHECKLIST) do Checklist.running end role(:CLAIMER) { |requester| claimed_by_user(requester) } role(:RESPONDER) { |requester| responded_by_user(requester) } group( has_feature(RUNNING_CHECKLIST) & ( has_role(PUBLIC) | has_role(H1_PENTESTER) | has_role(WHITELISTED_REPORTER) | has_role(INVITATION_RECIPIENT_WITH_SATISFIED_REQUIREMENTS) ) | has_role(TEAM_MEMBER) | has_role(CLAIMER) | has_role(RESPONDER), ) do allow :checklist_check_responses allow :checklist_checks allow :expires_at allow :id allow :name allow :team allow :unclaimed_checklist_checks_count end end ``` At first sight, the authorization check seems to be implemented correctly. However, the `CLAIMER` role is leveraging the `claimed_by_user` scope, which is implemented as follows: ```ruby scope :claimed_by_user, lambda { |user| where(id: ChecklistCheck.where(user_id: user).select(:checklist_id)) } ``` Instead of an inner join, a query (`ChecklistCheck.where(user_id: user).select(:checklist_id)`) is used to fetch the checklist IDs that are claimed. Because not all checks are claimed, `user_id` can be set to `NULL` in the database. Because the HackerOne GraphQL endpoint can be queried as an anonymous user, this scope can be called with `nil`. This causes anonymous users to automatically get the `CLAIMER` role, thus exposing information about `Checklist` objects. The other protectors correctly implement the `claimed_by_user` scope. Any relations defined on the `Checklist` model, such as `team`, `checklist_check_responses`, and `checklist_checks` are protected separately and are not accessible by anonymous users. The exposed information is limited to `Checklist` objects, which doesn't expose any customer information. The following query can be used to query a `Checklist` object. Make sure you're signed out when executing this query. ``` query { node(id: "Z2lkOi8vaGFja2Vyb25lL0NoZWNrbGlzdC8x") { ... on Checklist { name expires_at } } } ``` ## Impact Anonymous users can obtain information about checklists.

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Submitted

Weakness

Improper Access Control - Generic