Oturum aç Sonsuza kadar ücretsiz Başlayın
Security Blog

View Source, Copy Key, Own Everything

#2

April 27, 2026 · By Marketing team

← All posts

A researcher opened ClickUp's page source, found a hardcoded API key in the JavaScript, and used it to pull 959 email addresses and 3,165 internal feature flags in a single request. The key had no scope, no rate limit, and no expiry.

A security researcher went to clickup.com. Opened the page source. Found an API key hardcoded in the JavaScript. Copied it. Sent one GET request.

Got back 959 email addresses and 3,165 internal feature flags. Employees from Home Depot. Fortinet. Autodesk. Tenable. Rakuten. Mayo Clinic.

One string. One request. Everything.

How this happens

Someone needed the frontend to call an API. The API required authentication. So they put the key in the JavaScript. Ship it, move on, next sprint.

This isn't a sophisticated attack. There's no exploit, no zero-day, no social engineering. It's view-source: and curl. A browser and a terminal. The kind of thing a curious intern does on their first day.

The key had no scope — it could access everything the API exposed. No rate limit — one request returned everything. No expiry — the key worked until someone noticed. No second factor — possession of the string was the only gate.

The money angle

People talk about data exposure. Let's talk about what this data is worth.

959 corporate email addresses from Fortune 500 companies. That's a spear-phishing target list that threat actors pay for. Names, roles, and the fact that these companies use ClickUp — that's the social engineering context that makes phishing work.

3,165 internal feature flags. That's a roadmap. It tells competitors what ClickUp is building, what they're testing, what's behind a gate. It tells attackers which features are half-built and likely vulnerable.

This isn't a privacy incident. It's a business intelligence leak.

Why this keeps happening

This is the fourth credential-in-source incident we've written about this month. Bitwarden's CLI had credentials harvested because they were plaintext files. Vercel's environment variables were decryptable because the "sensitive" flag wasn't default. A developer lost 634 Chrome passwords because the decryption key was on the same disk.

The pattern is always the same: a credential exists as a string — in a file, in a variable, in page source — and something reads it. The something changes. The pattern doesn't.

API keys in JavaScript are the most egregious version because there's no attack required. The key is published. It's served to every visitor. The browser downloads it, renders it, and shows it to anyone who right-clicks.

What should have been different

The API call should never have been authenticated with a static key from the client side. The options:

  • Backend proxy. The frontend calls your own backend, which holds the key server-side and proxies the API call. The key never reaches the browser.
  • Session-scoped tokens. The frontend gets a short-lived, narrowly-scoped token after authentication. It expires. It can only do what the authenticated user is allowed to do. It's not a master key.
  • No key at all. If the data is public, serve it without authentication. If it's not public, don't serve it to unauthenticated JavaScript.

Hardcoding an API key in client-side code is putting your house key under the doormat and publishing your address.

The credential lifecycle problem

This ClickUp key was probably created once, pasted into a JavaScript file, committed to a repo, deployed to production, and never thought about again. Nobody rotated it. Nobody scoped it. Nobody set an expiry. Nobody monitored what it accessed.

That's the lifecycle of most API keys in most organizations. Created in a hurry, pasted where they're needed, forgotten. They accumulate across codebases, config files, CI/CD pipelines, and apparently page source — each one a door that never locks.

The question isn't whether your organization has a key like this. The question is how many you have, and whether you'd know if someone copied one today.