Zigazoo advertises itself as “The World’s Largest Social Network For Kids”, and with a purported 12 million users that’s not an unreasonable claim. Originally launched in 2020 as an education-focused app with project-based learning challenges, Zigazoo has since positioned itself as a “safe” alternative in a potential post-Tik-Tok landscape. They’ve made a lot of progress into becoming the Tik-Tok alternative, teaming up with Chuck E. Cheese, iHeartMedia, partnering with brands for in-app content and contests (like Sephora and NBCUniversal), and receiving multiple celebrity endorsements (here’s Serena Williams, who is also an investor). They also have their own in-app kid influencer “Creator Club”.
Zigazoo also incorporated NFT sales in the app after a 2022 $17M funding round. They elaborate on this in their Flow “Partner Spotlight”:
Zigazoo’s mission for bringing NFTs directly to kids is to provide a safe space for them to express their creativity and teach imperative aspects of Web3 and financial literacy that will be the basis of the future economy.
(I did not interact with this part of the app, but the “Does a Toddler Need an NFT?” article is a good source of what this looks like in practice.)
Notably, Zigzaoo is a member of the kidSAFE program, with a “kidSAFE+ COPPA-CERTIFIED Seal (FTC-Approved “Safe Harbor”)” seal, a membership level which requires “Data integrity and security procedures”. Their own “Safety & Positivity” page states they’re building an “airtight secure environment”. They’ve even participated in multiple events around “Social Media Wellness Month”, including a roundtable with the Family Online Safety Institute and visits to Senator Edward Markey’s office, who recently re-introduced COPPA 2.0. Despite all this, Zigazoo had a number of low complexity, critical security issues with serious impact to user privacy and application integrity. Effectively, anyone could:
- View, modify, and query all user records (which can include email, full name, parent’s email address, verified phone number, birth year, geolocation of the last IP used, and valid Firebase refresh tokens)
- Anonymously view all uploaded user content, regardless of moderation status or privacy settings, including videos users have deleted
- Escalate an account to become a Channel or Moderator
- Impersonate other users
- Modify some uploaded media of other users, regardless of moderation status
I delayed disclosure of these issues until all of them had been addressed by Zigazoo. This ended up taking over nine months from Zigazoo’s acknowledgment (9/11/2024) until the final remaining incomplete fixes were addressed (6/23/2025). More information can be found in the Remediation and Retesting and Disclosure Timeline sections.
The purpose of this post is threefold:
- Reinforce the privacy and security obligations that companies have if they choose to build applications around sensitive data or vulnerable user populations.
- Illustrate the difficulty parents have in evaluating apps and the potential danger of relying on third-party certification. (I believe the Apple App Store and Google Play also contribute to this by continuing to list Zigazoo in their “Educational” categories. Zigazoo’s own app descriptions have no pretense of it providing educational content and instead promise “Become a star!”, “Safe TikTok for Kids”, “Go Viral”, etc. A quick scroll through trending tags and leaderboard shows nothing but children mimicking the standard TikTok influencer #grwm/#dances/#haul fare.)
- Provide yet another example of Firebase being one of GCP’s worst footguns.
I would like to thank the Electronic Frontier Foundation for their advice and all the time they spent with me during this disclosure process. I also found their Coders’ Rights Project to be an invaluable resource for anyone pursuing this kind of research. If you would like to support the EFF’s mission, please consider donating. (They were even able to find someone to meet with me in the literal final hour of DEF CON 32 after I made first contact during the closing ceremony. Just amazing people.)
Public Buckets
My initial findings started in August, 2024 while I was attending DEF CON 32. Some of my automated tooling stumbled across a Google Cloud Storage (GCS) bucket in a Zigazoo staging GCP project and the bucket was misconfigured to allow allUsers
full list
/read
access to the entire bucket, meaning anyone could anonymously browse and download every object in the bucket. Once I got back home and had time to do a little bit more investigating, it turned out their production bucket was similarly misconfigured. (I should point out that this bucket name is not hard to find and is referenced directly in a number of public resources. I later discovered I was not the first person to discover this bucket, but was the first to report it.)
The production bucket appeared to hold all the uploaded content from all users, including:
- Parental consent videos
- Challenge “response” videos
- Profile images
In later testing, I was able to determine that these files are visible immediately after a user has uploaded them and is not affected by any private/public setting from the user nor by moderation status.

Zigazoo production bucket, showing a selection of user uploaded videos and photos.
Additionally, GCS Object Versioning was enabled on the bucket. This means when a user deleted a video in the app the live version of the uploaded content is deleted from the bucket, but a noncurrent object version is retained. This means deleted videos from any user were recoverable by anyone by explicitly listing and requesting noncurrent versions. For example, I could recover a test video I uploaded and deleted using the gsutil
CLI or the GCS web console:
# there are no live objects for my user in the bucket
➜ ~ gsutil ls gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos
CommandException: One or more URLs matched no objects.
# noncurrent versions are still available, '-a' option includes non-current object versions in the results
➜ ~ gsutil ls -a gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos
gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos/b61e8790-2f3d-11f0-aa09-9b1dd1655c57.jpg#1747060271302585
gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos/b61e8790-2f3d-11f0-aa09-9b1dd1655c57.mp4#1747060255724723
gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos/b61e8790-2f3d-11f0-aa09-9b1dd1655c571747060270704__optimized.mp4#1747060272334201
gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos/b61e8790-2f3d-11f0-aa09-9b1dd1655c57_screenshot.jpg#1747060271233727
gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos/b61e8790-2f3d-11f0-aa09-9b1dd1655c57/
gs://<bucket-name>/R6LLZNzETTfAINifdb9CgZvlEqt2/videos/b61e8790-2f3d-11f0-aa09-9b1dd1655c571747060270704__optimized/
Firestore Backups
One interesting thing in the staging bucket was a number of older Firestore exports from 2020. These included a number of users’ email addresses, etc, but also tipped the names of Firestore collections that would be useful in later testing.

Firestore backup, showing collections and user documents.
At this point I had tried for a couple of weeks to contact Zigazoo by email without a response. So, knowing there’s a couple of rudimentary GCS misconfigurations and that the app uses Firebase, I decided to take a closer look at the Android application itself to see what issues may be lurking there.
Firebase
Firebase is Google’s Backend-as-a-Service offering and is popular in mobile development since it can simplify development, as it provides turnkey authentication, object storage, and data storage without any custom backend deployments needed. This means clients interact directly with Firebase APIs, so data security must be enforced with Firebase Security Rules. Unfortunately, these rules can be (notoriously?) difficult to configure and many developers simply overlook them entirely.
There’s a long history of very similar security issues due to Firebase rule misconfigurations. Just a few examples:
- gaining access to anyones browser without them even visiting a website
- Firebase: Insecure by Default
- 900 Sites, 125 million accounts, 1 vulnerability
- Report: Estimated 24,000 Android apps expose user data through Firebase blunders
- Firebase: Google Cloud’s Evil Twin
Authentication
The user creation flow in the Android app goes through a couple of steps before you can create an account. First, you’re presented with an age selection dialog that goes from 1 to 16. Then you’re prompted to answer a simple multiplication problem before being allowed to continue with account creation, the parental consent video, and age verification (provided by Kids Web Service).
However, Zigazoo is using Firebase’s federated auth (“Login with Google”) and Email & Password authentication service. That means I could just create a Firebase user by calling the Google Identity Toolkit signupNewUser
API directly, skipping any email or age verification, or even using the app at all. All I needed was Zigazoo’s Firebase API key, which was hardcoded in a number of public resources (like the app apk / bundle). The signup request’s only other requirements are an email string that needs to pass a weak regex and password that’s a minimum of six characters (there’s no other complexity rules):
➜ ~ curl --request POST \
--url 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=<api-key>' \
--header 'content-type: application/json' \
--data '{"email":"[email protected]", "password":"123456", "clientType":"CLIENT_TYPE_ANDROID"}'
This returns an idToken
that I could use to interact directly with Firebase, a refreshToken
that is used to renew it, and a localId
that would be used as my uid
/userId
in the app.
{
"kind": "identitytoolkit#SignupNewUserResponse",
"idToken": "<snip>",
"refreshToken": "<snip>",
"expiresIn": "3600",
"localId": "Ei6wYeu7CBbeaYvcHchjFqXLcRe2"
}
This appears to be counter to their Verified, Secure Sign-Up Process statement:
In order to sign up to use Zigazoo, you must get verified through either your phone number or single sign-on with Google or Apple accounts. There is no random creation of accounts.
Reading User Records
Using a Firebase idToken
and the knowledge of the Firestore collection names from the backups exposed in the public buckets, I could then request documents from the users
collection directly from Firestore. (The backups aren’t necessary to know the collection names, they’re exposed in the APK bundle as well in client-side calls that can be captured through proxying.) It didn’t appear there were any appropriate Firestore Security Rules in place, so I could perform a number of read actions against the users
collection:
- Read any individual
users
record byuid
. - Query the
users
collection. - Dump the entire
users
collection.
The uid
values aren’t secret, they’re used as public references to users in almost every API call. Also, being able to read individual records means I would be able to correlate videos from the public buckets to specific users, since the bucket’s keys include the uid
of the uploader. The query ability would allow me to filter results by common criteria, like find all moderators, all users with a rough geolocation in a particular state, or simply find an individual user by their email address.
For example, reading a single user’s record was a simple GET
to the Firestore API, using a Firebase idToken
as a bearer token:
curl -s -H "Authorization: Bearer $TOKEN" \
"https://firestore.googleapis.com/v1/projects/<project-id>/databases/(default)/documents/users/<uid>"
The users
records contained a number of sensitive fields that are not publicly displayed in the app:
email
birthYear
displayName
(the Google Account Name of the associated email, commonly the user’s full name)parentEmail
andverifiedPhoneNumber
lastCheckInLocation
(the city, state, and lat/long of the last IP used, not GPS data)refreshToken
Firestore wasn’t the only source of leaking user records. There was also an API used within the application that as part of the response returned a collection of related users, but returned the entire user record instead of a subset of safe fields.
Modifying User Records & Account Escalation
Due to the lack of appropriate Firestore Security Rules, it was also possible to modify any existing users
record. This could be used to make changes to account info, verification, or privacy settings for any user. It also would allow me to promote my testing account’s type from an unverified user to become a “verified brand”/channel or even an admin/moderator. Moderators can access the content moderation queue and could conceivably approve or upload any content.

Test user’s profile as a moderator (left) and as a verified brand (right).
Impersonating Other Users
The refreshToken
stored in some users
records could be used to login to Zigazoo by proxying the application’s call to the Google Identity Toolkit verifyPassword
endpoint and returning a custom response. This would allow someone to use the application as any user that had a valid refreshToken
stored in Firestore and would not require actually knowing the user’s password or going through any federated login.
The response from https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword
looks like this:
{
"kind": "identitytoolkit#VerifyPasswordResponse",
"localId": "<uid>",
"email": "<email>",
"displayName": "",
"idToken": "<idToken>",
"user_id": "<uid>",
"registered": true,
"refreshToken": "<refreshToken>",
"expiresIn": "3600"
}
All of these values could be obtained from just starting with a valid refreshToken
and using it to request an idToken
via Google Identity Platform’s token
API using the app’s Firebase API key:
➜ ~ cat token-payload.json
{
"grantType": "refresh_token",
"refreshToken": "AMf-vBylmLrnS<snip>"
}
➜ ~ curl -X POST -H "Content-Type: application/json" \
-d @token-payload.json \
https://securetoken.googleapis.com/v1/token\?key\=<snip>
{
"access_token": "eyJhbGciO<snip>",
"expires_in": "3600",
"token_type": "Bearer",
"refresh_token": "AMf-vBylmLrnS<snip>",
"id_token": "eyJhbGciO<snip>",
"user_id": "<snip>",
"project_id": "<snip>"
}
That gets the idToken
and refreshToken
needed for the custom verifyPassword
response. The remaining values can be determined from the claims of the returned user_id
JWT:
{
"iss": "https://securetoken.google.com/<snip>",
"aud": "<snip>",
"auth_time": 1726155454,
"user_id": "<uid>",
"sub": "<uid>",
"iat": 1726155615,
"exp": 1726159215,
"email": "<email>",
"email_verified": false,
"firebase": {
"identities": {
"email": [
"<email>"
]
},
"sign_in_provider": "password"
}
}
The example here shows me logging into Zigazoo as my test user, abp-test
, without using a real username & password. This is possible because the verifyPassword
request is being caught by my proxy and the successful login response is generated starting from just abp-test
’s refreshToken
.
Modifying Other User’s Uploads
Zigazoo also uses Firebase Cloud Storage, which provides a Firebase-native way to interact with Google Cloud Storage buckets. It has its own Security Rules, and just like Firestore, there didn’t appear to be any applicable rules that would stop me from writing to any path in Zigazoo’s primary storage bucket. This gave me the ability to overwrite anything that’s served directly from this bucket, which appears to include user profile images and video thumbnails. Videos themselves are served via a CDN and appear to originate from a different bucket so this issue wouldn’t allow you to direcly modify videos that are served to the app. I didn’t want to modify anything that’s publicly visible, so no files were modified outside of my test users and the proof-of-concept file I reported to Zigazoo.
The call is simply a POST
to the Firebase Storage API with the target path and file content:
➜ ~ curl --request POST \
--url 'https://firebasestorage.googleapis.com/v0/b/<bucket>/o?name=<url-encoded-path>&uploadType=resumable' \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: <mime-type>" \
--data-binary @<local-file>
Remediation and Retesting
The remediation and retesting process for these issues took more than nine months from my initial successful contact with Zigazoo to validating the final fixes. The Disclosure Timeline shows a repeated pattern of delayed deadlines, deferred testing, and a lack of promised proactive updates. There was also confusion from Zigazoo about my intentions and public disclosure in general, which led to a number of questions (“Can Zigazoo stay anonymous?”, “Are you being paid for this?”, “Can you write it in conjuction with our 3rd-party testers?”, “Why publicly disclose, since it brings additional scrutiny from hackers?”, etc).
In November 2024, three months after my initial report, Zigazoo decided they would like a 3rd party security assessement before they were comfortable with me retesting the reported issues and going ahead with disclosure. In January 2025 I attended the “kickoff” call for this engagement with myself, Zigazoo, kidSAFE, and the 3rd-party security testing company. Before the whole group joined, I explained the issues I’d reported to the Zigazoo engineer on the call, who had no follow-up questions. (This was the only engineer I ever spoke to.) The call itself was a standard corporate scheduling affair, who will email who, when, etc. I was not asked any questions during this part and I only spoke up when the topic of an NDA came up to clarify that I was not a Zigazoo employee, but an outside security reporter and would not be signing an NDA, so please do not include me in those emails, thanks. (I’m refraining from naming the 3rd-party testing group because, while I had assumed my finding’s details were shared with them, I have no details about their engagement or scope.) In the following period, I asked Zigazoo for updates roughly every four weeks and if they were prepared for retesting without ever getting a go-ahead.
In May 2025 I discovered that the internet asset scanner odin.io had also found and indexed Zigazoo’s primary GCS bucket in July 2024, a month before my tooling found it. I was dismayed to see that the odin.io index to the bucket content still worked, and you could still list all content, but only if you were logged into a Google account. That behavior suggested that Zigazoo had hit another one of GCP’s classic footguns and changed the bucket’s ACL from allowing allUsers
, which includes anonymous requests, to allAuthenticatedUsers
, which includes anyone authenticated with a Google Account, not just principals associated with that particular GCP project. (GCP’s own IAM principals documentation points out the functional difference between these two roles is pretty much moot.)
The realization that the bucket was previously discovered and remained accessible prompted me to no longer wait for an update from Zigazoo and to go ahead and re-test my findings. It turned out two issues were still not completely fixed:
- The primary GCS bucket could still be enumerated by anyone authenticated with a Google account
- Firestore still allowed for arbitrary field updates to a user’s own record, allowing them to escalate themselves to moderator/admin
I reported this to Zigazoo on 5/14/2025, followed up again on 6/18/2025 along with a 45 day disclosure notice, and validated both issues were fixed on 6/24/2025.
Zigazoo Statement
On 7/17, Zigazoo supplied the following statement:
We’re grateful for Ian’s communication. With his input, along with that of other cybersecurity experts, we’ve strengthened our backend to help keep our community safe. We have found no evidence that our community’s data or security were ever compromised. Today, our backend architecture is more resilient, more robust, and better prepared than ever to scale securely.
As well as this statement from TÜV Rheinland, the 3rd-party testing company Zigazoo worked with:
Following industry standards, Zigazoo underwent TÜV Rheinland’s comprehensive testing for mobile application cybersecurity. This collaboration enhances the overall security posture of the Zigazoo application. We are thrilled to see kids companies like Zigazoo leading an important movement to ensure kids’ data is safe and secure.
They have also updated their site to include a Cloud and Data Security Commitment page.
Disclosure Timeline
- 8/16/2024 - Emailed [email protected] (automated response), [email protected] (bounced)
- 8/23/2024 - Emailed the CEO and Director of Impact at their
@zigazoo.com
addresses, both of which were in the Firestore backups or included on the Google Play listing for Zigazoo (no response) - 8/29/2024 - Emailed [email protected] (automated response)
- 8/29/2024 - Messaged the COO/CMO on LinkedIn (no response, was later informed they no longer worked at Zigazoo but was still listed as COO/CMO)
- 9/5/2024 - Sent invite + note to “Strategic Growth and Operations” lead on LinkedIn (no response)
- 9/9/2024 - Sent invite + note to CEO and Director of Impact on LinkedIn (immediate response from CEO, who says he will contact my employer if I don’t respond within an hour)
- 9/9/2024 - CEO responds, I respond with timeline up to then, denies receiving emails, asks to get writeup emailed to the same address
- 9/9/2024 - Sent initial writeup + examples
- 9/9/2024 - Zigazoo acknowledges receiving writeup
- 9/11/2024 - Zigazoo responds to writeup email “working to fix and resolve this asap”
- 10/1/2024 - Zigazoo responds that fixes will be completed by 11/4
- 10/30/2024 - Sent email asking for update on 11/4 completion and asking if they’d like me to re-test
- 10/30/2024 - Zigazoo responds, pushing deadline to 11/15 and asking if Zigazoo would be named in my disclosure
- 10/30/2024 - I respond that I can wait until 11/15 and that Zigazoo would be named in my disclosure
- 11/7/2024 - Zigazoo emails, saying “everything is in progress” and asks for clarification about what my disclosure would look like / where it would be published
- 11/7/2024 - I respond with an outline of my disclosure, along with links to a number of examples of other public disclosures
- 11/14/2024 - Zigazoo emails, pushing deadline to “at least until December 15th”, asks for clarification as to why I’d pursue public disclosure considering “the obvious side effect of more hackers trying to access extremely sensitive information”
- 11/14/2024 - I agree to 12/15, but say I’d like to avoid extending again since that would be 90 days from initial disclosure and clarify the appropriate nature of public disclosure and it’s benefit to consumers for making informed decisions
- 11/22/2024-1/10/2025 - At this point Zigazoo decides they want a 3rd-party security evaluation and I agree to wait until that engagement is complete if Zigazoo “believes an external security engagement would get you to a place where you feel [the issues] have been addressed and can be re-tested”. Zigazoo ends up partnering with kidSAFE and a 3rd-party testing company, with a kickoff and call scheduled in January 2025
- 1/10/2025 - Attended a “kickoff” meeting with Zigazoo, kidSAFE, and the 3rd-party security testing reps
- 1/17/2025 - Followed up on status, since it sounded like Zigazoo was close to completing fixes from the previous week’s call
- 1/18/2025 - Zigazoo responds, asking to hold off testing until the 3rd-part “pentest” is complete
- 2/21/2025 - Sent email checking in on status of 3rd-party engagement, can I re-test reported issues
- 2/24/2025 - Zigazoo responds, still waiting on 3rd-party results, please wait on testing
- 3/31/2025 - Sent email checking in status of 3rd-party engagement, express concern about current timeline (six months) and completeness of existing work Zigazoo has done
- 4/1/2025 - Zigazoo responds, they received results from 3rd-party, doing remediation on those findings, please wait while those are re-tested
- 4/2/2025 - I respond, again reiterating that I don’t believe Zigazoo’s fixes to my reported issues are complete but will wait on re-testing if Zigazoo believes their 3rd-party review will fully address them
- 5/14/2025 - Sent email stating that the odin.io bucket indexing (with link) has prompted my re-testing (since I had received no updates from Zigazoo), reported primary bucket still list/read and arbitrary Firestore field writes are still allowed to user’s own record
- 5/15/2025 - Zigazoo responds, “just finished completing all items for our pen test”, will be in contact as they continue
- 6/18/2025 - Sent email notifying Zigazoo that in light of odin.io’s discovery and the lack of action on the remaining security issues (bucket access, firestore writes) I will be publishing my writeup in 45 days
- 6/23/2025 - Zigazoo responds, looking into two remaining issues
- 6/24/2025 - Remaining issues are re-tested and appear fixed
- 7/10/2025 - Notified Zigazoo of 7/21 publication date
- 7/17/2025 - Zigaoo provided statements for inclusion in this writeup
- 7/21/2025 - This writeup is published