Airbuds.fm: GraphQL Privacy Oversight in a Social Music App

🧠 Why I Looked Into This

In early October 2024, I started investigating the Airbuds.fm app. At the time, it had grown to over 3 million users and ranked among the top 10 music apps on the App Store. Airbuds.fm is a social music app that lets users share listening activity and weekly music stats with friends.

Like many mobile apps, it uses a GraphQL API on the backend—a pattern I’ve seen repeatedly across mobile platforms. This would be the third app in a row I’ve reviewed with significant GraphQL security concerns.


šŸ” Initial Discovery

āœ… Introspection Query Disabled

First check: introspection. Many GraphQL vulnerabilities start with the schema being exposed via an introspection query:


  graphqlCopyEditquery IntrospectionQuery {
  __schema {
    queryType { name }
    types {
      name
      fields { name }
    }
  }
}


In Airbuds.fm’s case, they followed best practices and had introspection disabled in production. That’s a win.

But that didn’t stop the investigation.


šŸ“Š Native Query Analysis

Without introspection, I turned to traffic from the app itself using a MITM proxy. I identified three key GraphQL operations to investigate:

1. SendDM

graphqlCopyEditmutation SendDM($message: String!) {
  sendDM(message: $message) {
    id
    text
    createdAt
  }
}

2. ReactToFeedActivity

graphqlCopyEditmutation ReactToFeedActivity($reaction: CreateFeedActivityReactionInput!) {
  reactToFeedActivity(reaction: $reaction) {
    __typename
  }
}

3. UserProfile and Me

graphqlCopyEditquery Me {
  me {
    profileURL
    phone
    phoneVerified
    birthdate
  }
}

query UserProfile($identifier: String!) {
  user(identifier: $identifier) {
    profileURL
  }
} 

These gave me the groundwork for two lines of testing:

  • Character limit abuse
  • Parameter modification for sensitive data exposure

šŸ Character Limit Testing

For abuse testing, I use the Bee Movie script—a large block of text that serves as a simple stress test.

šŸ“¬ DM Injection

I used the Bee Movie script as a direct message:

āœ… It sent successfully
āœ… No app crash
āœ… Full render, screenshot captured

šŸŽµ Emoji Reaction Abuse

I injected the Bee Movie script as a song reaction emoji:

āœ… Successfully submitted
šŸ’„ Crashed the app when scrolling past the affected post
🧹 Resolved by deleting the reaction using a modified delete query

These tests confirmed the absence of input limits on both endpoints—client-side checks were in place, but server-side validation was missing.


šŸ”“ Unauthorized Data Exposure

The most impactful finding came from modifying the UserProfile query to match the structure of the authenticated Me query:

graphqlCopyEditquery UserProfile($identifier: String!) {
  user(identifier: $identifier) {
    profileURL
    phone
    phoneVerified
    birthdate
  }
}

āœ… Result:

jsonCopyEdit{
  "data": {
    "user": {
      "profileURL": "https://i.airbuds.fm/redacted",
      "phone": "REDACTED",
      "phoneVerified": true,
      "birthdate": "REDACTED"
    }
  }
}  

Despite being unauthenticated, this query returned private user data, including:

  • Phone numbers
  • Birthday
  • Phone verification status

While the attack surface was narrowed by requiring valid usernames, with automation this could be used to scrape PII at scale.


🧠 Key Lessons & Recommendations

āœ… Wins:

  • Introspection disabled
  • DM and profile endpoints rejected spoofing attempts

āš ļø Issues Identified:

  1. No character limit on message and emoji inputs
  2. Sensitive fields exposed through unauthorized parameter injection
  3. No field-level access controls on public queries
  4. Client-side checks not mirrored server-side

šŸ” Recommendations for Devs

  • Enforce input validation server-side, not just in the client
  • Limit character length on all user-input fields (emoji, DM, bio, etc.)
  • Implement strict field-level access control
  • Disable unnecessary fields in public queries
  • Regularly test your GraphQL schema using manual and automated abuse simulation

šŸ’¬ Final Thoughts

Airbuds.fm isn’t the first app I’ve seen with these issues—and won’t be the last. GraphQL APIs are flexible but unforgiving if you don’t secure them properly.

This app did take important precautions like disabling introspection and rejecting unauthorized user spoofing. But it also had avoidable oversights in data exposure and payload validation.

For security researchers, this case is a reminder: just because introspection is disabled doesn’t mean an API is safe.

Read more