Security Blog

Bekijk de bron, kopieer de sleutel, bezit alles

#48

October 2, 2026 · By Marketing team

← All posts

Een onderzoeker opende de broncode van ClickUp, vond een hardcoded API-sleutel in de JavaScript en gebruikte die om in één verzoek 959 e-mailadressen en 3.165 interne feature flags op te halen. De sleutel had geen scope, geen rate limit en geen vervaldatum.

Een securityonderzoeker ging naar clickup.com. Opende de broncode. Vond een API-sleutel die hardcoded in de JavaScript stond. Kopieerde die. Stuurde één GET-verzoek.

Kreeg terug: 959 e-mailadressen en 3.165 interne feature flags. Medewerkers van Home Depot. Fortinet. Autodesk. Tenable. Rakuten. Mayo Clinic.

Eén string. Eén verzoek. Alles.

Hoe dit gebeurt

Iemand wilde dat de frontend een API aanroept. De API vereiste authenticatie. Dus zetten ze de sleutel in de JavaScript. Shippen, door, volgende sprint.

Dit is geen geraffineerde aanval. Geen exploit, geen zero-day, geen social engineering. Het is view-source: en curl. Een browser en een terminal. Het soort dat een nieuwsgierige stagiair doet op zijn eerste dag.

De sleutel had geen scope — hij kon bij alles wat de API blootgaf. Geen rate limit — één verzoek leverde alles op. Geen vervaldatum — de sleutel werkte tot iemand het merkte. Geen tweede factor — het bezit van de string was de enige barrière.

Het geldaspect

Mensen praten over datalekken. Laten we het hebben wat deze data waard is.

959 zakelijke e-mailadressen van Fortune 500-bedrijven. Dat is een spear-phishing-doelwitlijst waarvoor threat actors betalen. Namen, functies, en het feit dat deze bedrijven ClickUp gebruiken — dat is de context voor social engineering die phishing laat werken.

3.165 interne feature flags. Dat is een roadmap. Het vertelt concurrenten wat ClickUp bouwt, wat ze testen, wat achter een poort zit. Het vertelt aanvallers welke functies half af zijn en waarschijnlijk kwetsbaar.

Dit is geen privacy-incident. Het is een lek van bedrijfsinformatie.

Waarom dit blijft gebeuren

Dit is het vierde credential-in-broncode-incident deze maand waar we over schrijven. Bij de CLI van Bitwarden werden credentials buitgemaakt omdat het platte tekstbestanden waren. De environment variables van Vercel waren te ontsleutelen omdat de vlag "sensitive" niet standaard stond. Een ontwikkelaar verloor 634 Chrome-wachtwoorden omdat de ontsleutelingssleutel op dezelfde schijf stond.

Het patroon is altijd hetzelfde: een credential bestaat als string — in een bestand, in een variabele, in de broncode van een pagina — en iets leest die. Het "iets" verandert. Het patroon niet.

API-sleutels in JavaScript zijn de meest schandalige variant, want er is geen aanval nodig. De sleutel wordt gepubliceerd. Hij wordt aan elke bezoeker geserveerd. De browser downloadt hem, rendert hem, en toont hem aan iedereen die met rechtsklikt.

Wat er anders had gemoeten

Het API-verzoek had nooit geauthenticeerd mogen worden met een statische sleutel vanaf de client. De opties:

  • Backend-proxy. De frontend roept je eigen backend aan, die de sleutel server-side bewaart en het API-verzoek proxied. De sleutel komt nooit in de browser.
  • Tokens met sessiescope. De frontend krijgt na authenticatie een kortlevende, smal gescopeerde token. Die verloopt. Die kan alleen wat de geauthenticeerde gebruiker mag doen. Het is geen mastersleutel.
  • Helemaal geen sleutel. Als de data publiek is, serveer hem dan zonder authenticatie. Als hij niet publiek is, serveer hem dan niet aan niet-geauthenticeerde JavaScript.

Een API-sleutel hardcoden in client-side code is je huissleutel onder de deurmat leggen en je adres publiceren.

Het lifecycleprobleem van credentials

Deze ClickUp-sleutel is waarschijnlijk één keer aangemaakt, in een JavaScript-bestand geplakt, in een repo gecommit, naar productie gedeployd, en daarna nooit meer aan gedacht. Niemand heeft hem geroteerd. Niemand heeft hem gescopeerd. Niemand heeft een vervaldatum gezet. Niemand heeft gemonitord waar hij bij kon.

Dat is de lifecycle van de meeste API-sleutels in de meeste organisaties. In haast aangeplakt waar ze nodig zijn, en vergeten. Ze hopen zich op in codebases, configbestanden, CI/CD-pipelines, en blijkbaar in broncode van pagina's — elk een deur die nooit op slot gaat.

De vraag is niet of jouw organisatie zo'n sleutel heeft. De vraag is hoeveel je er hebt, en of je het zou weten als iemand er vandaag een kopieerde.