Overview

While exploring Airbnb's support message system, I found that an authenticated user can access partial metadata of another user's support thread just by manipulating the globalThreadId parameter in the ViaductGetThreadAndDataQuery GraphQL endpoint. Instead of returning a proper HTTP 403, the server comes back with HTTP 200 and thread metadata that doesn't belong to you.

"Being able to know if a user has an active conversation does not appear to pose a security risk." - Airbnb Security Team (Closed as Informative)

What Gets Leaked

The message content itself is protected, but the endpoint still leaks a bunch of metadata when you supply an unauthorized globalThreadId. Things like thread ID and existence confirmation, inbox visibility status via hiddenInInbox which actually reveals whether an account is under moderation, activity timestamps, and profile images of the support participants.

Steps to Reproduce

Step 1 - Setup two Airbnb accounts:

Account A - Attacker
Account B - Victim (test account)

Step 2 - Get the victim's thread ID from the URL:

Login as Account B, open support chat and grab the thread ID from the URL.

Victim Thread URL

Step 3 - Encode the thread ID to Base64:

$ echo -n "MessageThread:[REDACTED]" | base64
[REDACTED_BASE64]
Base64 Encoding in Terminal

Step 4 - Intercept and modify the request in Burp Suite:

Login as Account A, intercept the ViaductGetThreadAndDataQuery request, swap the globalThreadId value with the encoded victim thread ID, and send it via Repeater.

Burp Suite Repeater Request

Step 5 - Server returns HTTP 200 instead of 403:

HTTP 200 Response

Step 6 - Metadata of Account B leaked in the response body:

Leaked Metadata in Response Body

Proof of Concept

GET /api/v3/ViaductGetThreadAndDataQuery/d8dbf8f7...
  ?operationName=ViaductGetThreadAndDataQuery
  &variables={"globalThreadId":"[REDACTED_BASE64]"...}
Cookie: [Account A session]

--- Response ---
HTTP/2 200 OK
{
  "data": {
    "threadData": {
      "id": "[REDACTED]",
      "hiddenInInbox": true,
      "inboxAccessibilityTemplateText": "You do not have access to this thread.",
      "inboxProfileImages": [...],
      "mostRecentInboxActivityAtMsFromROS": "0",
      "fetchedAt": "[REDACTED]"
    }
  }
}

Impact Analysis

The message content is protected sure, but the metadata that leaks is still useful for an attacker. You can confirm whether a target has active support conversations, check if an account is under moderation review via hiddenInInbox: true, get a rough idea of their activity patterns from the timestamps, and enumerate valid thread IDs to chain into further attacks.

Remediation

The fix is straightforward. Return HTTP 403 for the entire request when the user isn't authorized, not just for the message content. Validate thread ownership server-side before returning any field at all. And make sure the authorization checks are consistent across all GraphQL field resolvers in that endpoint, not just the ones that return the actual messages.

Lessons Learned

Not every finding gets accepted, and that's just part of the game. What matters is the process, endpoint enumeration, response behavior analysis, structured reporting. Metadata disclosure gets underrated a lot, but in the right context it can be a stepping stone for something bigger. Keep hunting.
GraphQL IDOR Burp Suite Authorization Bypass Metadata Disclosure HackerOne Airbnb