Claude Code: Hunting Account Takeover Vulnerabilities in Granola

PromptCube Novice 1h ago 55 views 7 likes 2 min read

Security flaws in modern AI-integrated apps usually hide in the way they handle session tokens or third-party authentication. I managed to find a one-click account takeover (ATO) in Granola that also granted access to the user's webcam—a pretty massive privacy leak for a productivity tool.

The Vulnerability Path

The issue stemmed from a flawed implementation of the OAuth flow combined with improper session validation. Essentially, the application didn't strictly verify the state parameter during the callback, allowing an attacker to craft a malicious link that forced a victim to link their account to the attacker's identity.

To replicate this as a real-world AI workflow for security testing, I used a combination of manual interception and some custom scripts to automate the request forging.

1. Capture the Auth Request: I monitored the network traffic during a standard login. I noticed the code and state parameters were being passed back to the redirect URI without sufficient cryptographic binding to the original user session.
2. Craft the Payload: By manipulating the callback URL, I could essentially "swap" the authentication context.
3. The Trigger: Once the victim clicked the crafted link, the session was hijacked. Because Granola requests webcam permissions for its core functionality (transcribing/recording meetings), the hijacked session inherited those active permissions.

Technical Breakdown

If you're doing a deep dive into LLM agent security or general app deployment, this is a classic example of why "trusting the client" is a mistake. The logic looked something like this in the backend:

// Hypothetical flawed logic
app.get('/auth/callback', async (req, res) => {
  const { code, state } = req.query;
  const token = await exchangeCodeForToken(code);
  
  // Problem: No verification that 'state' matches the session that initiated the request
  const user = await findUserByToken(token);
  req.session.userId = user.id; 
  res.redirect('/dashboard');
});

By bypassing the state check, the attacker controls who is logged into the current browser session.

Impact and Fixes

The fallout here is significant. Beyond just seeing a user's notes, the webcam access means an attacker could potentially trigger recordings or capture images without the user realizing the session had been compromised.

For anyone building an AI workflow or a SaaS app from scratch, here is the practical tutorial for preventing this:

  • Strict State Validation: Always generate a high-entropy random string for the state parameter, store it in a secure, HTTP-only cookie, and verify it matches the callback exactly.
  • PKCE Implementation: Use Proof Key for Code Exchange (PKCE) even for server-side apps to ensure the entity requesting the token is the same one that started the flow.
  • Permission Scoping: Don't grant "blanket" permissions. Request webcam access only at the moment of recording, rather than maintaining a persistent open door.

This kind of bug is exactly why I've been using Claude Code to audit my own config files; it's surprisingly good at spotting missing validation checks if you prompt it to look for specific OWASP top 10 vulnerabilities.
Industry NewsAI News

All Replies (3)

Q
QuinnPilot Novice 9h ago
Finally found the security documentation for Granola. For anyone worried about data handling, the full disclosure is right here: https://docs.granola.ai/help-center/policies/security-contri... Worth a skim if you're deploying this in a corporate environment.
0 Reply
Q
Quinn48 Advanced 9h ago
Did you check if the session token was being leaked through any referer headers?
0 Reply
R
RayTinkerer Novice 9h ago
Found a similar flaw last year with a misconfigured OAuth callback. Always a goldmine.
0 Reply

Write a Reply

Markdown supported