October 28, 2026 · 7 min read · James Hartley, IT Insights — ItInsightsWorld Security desk
Secrets seldom surface during a code review; they surface inside an incident report. A large-scale measurement study now gives defenders a baseline instead of a guess: scanning 7,256,531 public repositories on Gitee — China's largest home-grown Git hosting platform — ended with 26,400 unique verified-live credentials, among them an active organization-admin credential for a major enterprise AI platform and thousands of live cloud provider access keys. The underlying work was contributed as a guest post by independent security researcher Ben Zimmermann, produced with the Kingfisher team at MongoDB. What follows reframes it as checks, misconceptions and actions for security and platform teams.
Scope in one line: TruffleHog and Kingfisher were run against 7.25 Million public Gitee repositories, and every candidate was authenticated against the issuing vendor's API before it was counted.
Gitee launched in 2013 under OSChina and was chosen by China's Ministry of Industry and Information Technology as the national open-source code hosting platform. The defensively interesting part is not the mandate but the tooling gaps. Its public API is severely constrained: there is no paginated projects endpoint, and the on-site code-search feature appears to have been retired years ago. A 2021 attempt to study credential exposure on Gitee concluded that its APIs were too limited to scale the research. Visibility is thin for researchers, for the operator itself, and for anyone else.
As with any large Git platform, that blind spot sits on an attractive exposure surface:
Enumeration required combining many surfaces: the only official REST endpoint that returned useful data at scale, the platform's Explore feed, per-user repository and stargazer pages on the website, and the internal Elasticsearch widget behind the on-site search UI.
That endpoint was GET /api/v5/search/users?q=, queried with three-character prefix queries ( aaa , aab , ..., zzz ). Results were merged with usernames from the public Explore feed ( /explore/all?order=starred|popular|updated ), then expanded through each user's following list and the stargazers of popular repositories. The seed corpus reached 1,704,759 usernames.
Two per-user pages yield repositories: gitee.com/{user}/projects and gitee.com/{user}/stared_projects. Page 1 of /projects returns full HTML, while later pages are AJAX-paginated ( X-Requested-With: XMLHttpRequest ). The stargazer-list pages used during username bootstrap paginate the same way and also require a CSRF token extracted from the page-1 HTML.
A large fraction of the platform sits outside the social graph, so the same endpoint that backs the search UI was queried directly: so.gitee.com/v1/search/widget/wong1slagnlmzwvsu5ya , accepting a query ID, a q parameter, and pagination via from + size :
Unformatted
Code Snippet # elastic_scrape_repos.py
API_URL = "https://so.gitee.com/v1/search/widget/wong1slagnlmzwvsu5ya"
QUERY_ID = "1048"
PAGE_SIZE = 20
MAX_RESULTS = 200
async def fetch_page(session, username, offset=0, language=None):
params = {
"query": QUERY_ID,
"q": username,
"from": str(offset),
"size": str(PAGE_SIZE),
"sort_by_f": "",
}
if language:
params["编程语言"] = language # "programming language"
async with session.get(
API_URL,
params=params,
headers={**HEADERS, "userid": str(uuid.uuid4())},
) as resp:
resp.raise_for_status()
return await resp.json()
Each query returned at most 20 results per page under a hard cap of 200 results total ( from + size <= MAX_RESULTS ), regardless of how many matches actually existed. For specific usernames that was usually fine; for common usernames and trigram prefix queries the cap silently truncated results.
The widget's response includes Elasticsearch aggregations that bucket results by language ( 编程语言 ) and license ( 许可证 ). Where a per-username query was capped, it was re-issued once per language bucket that the first response had already returned, paginating inside each bucket and stopping as soon as a page came back shorter than PAGE_SIZE. For trigram prefix queries used to surface repositories not associated with any discovered user, the same idea extended into a BFS over a query tree: capped nodes split first by language, then by license, then by deeper prefix until each branch fit within 200 results. After deduplicating repository IDs across all sources, the working set was 7,256,531 unique public Gitee repositories.
Cloning and scanning 7.25 million repositories was handled in a single Python script using Modal , a serverless compute platform popular for AI workloads but well suited to most parallel jobs. TruffleHog and Kingfisher ran concurrently against every repository for increased coverage; each surface verified credentials the other missed, so running both caught more exposed credentials than either alone.
Figure 1. Dual-scanner pipeline architecture.

A multi-stage build pulls both scanner binaries from their upstream releases into a single Python base, plus git and OpenSSH for cloning:
FROM trufflesecurity/trufflehog:latest AS trufflehog
FROM ghcr.io/mongodb/kingfisher:latest AS kingfisher
FROM python:3.11-slim
COPY --from=trufflehog /usr/bin/trufflehog /usr/local/bin/trufflehog
COPY --from=kingfisher /usr/local/bin/kingfisher /usr/local/bin/kingfisher
RUN apt-get update && apt-get install -y git openssh-client && rm -rf /var/lib/apt/lists/*
One Modal function bare-clones each repository over SSH and runs both scanners concurrently as subprocesses against the same on-disk clone — TruffleHog with --only-verified , Kingfisher with --only-valid — writing hits to a shared findings volume:
@app.function(
image=image,
volumes={"/findings": volume},
timeout=300,
cpu=(0.125, 2.0),
memory=(256, 4096),
max_containers=350,
)
def scan(repo_url: str):
repo_name = repo_url.rstrip("/").split("/")[-1].removesuffix(".git")
clone_path = f"/tmp/{repo_name}.git"
ssh_url = repo_url.replace("https://gitee.com/", "git@gitee.com:")
subprocess.run(
["git", "clone", "--bare", "--quiet", ssh_url, clone_path],
capture_output=True, check=True,
)
th_proc = subprocess.Popen([
"trufflehog", "git", "--bare", f"file://{clone_path}",
"--json", "--only-verified", "--allow-verification-overlap",
], stdout=subprocess.PIPE, text=True)
kf_proc = subprocess.Popen([
"kingfisher", "scan", clone_path,
"--format", "jsonl", "--only-valid",
], stdout=subprocess.PIPE, text=True)
th_output = th_proc.communicate()[0].strip()
kf_output = kf_proc.communicate()[0].strip()
# ... write hits to the shared findings volume
The corpus was split into 50 batches of ~150K repos, then run sequentially at a steady 350 concurrent containers; smaller batches were safer at this scale and easier to resume after interruptions, while larger batches were unstable and hit clone-side blocks. Total wall time was roughly one month of continuous execution. Per-repo clone times were a major contributor: Gitee's servers sit in China, and network distance across the Pacific plus SSH protocol overhead made each clone materially slower than an equivalent GitHub clone. Total cost was $3,097.64, fully absorbed by the $5,000 compute-credit sponsorship from Modal that supported this research. The same Modal + dual-scanner architecture works against most Git hosts with little more than a clone-URL substitution; a smaller-scale version powered a prior investigation of Algolia DocSearch admin keys .
From those public repositories the pipeline surfaced 26,400 unique, verified-live credentials after deduplicating by token value. Both scanners authenticate each candidate against its vendor's API at scan time (TruffleHog's --only-verified and Kingfisher's --only-valid modes), discarding anything that pattern-matches but fails to authenticate, and the 26,400 figure is deduplicated by raw secret value, so duplicates across repositories or scanners count once.
| Scanner | Unique Findings |
|---|---|
| TruffleHog | 12,737 |
| Kingfisher | 14,664 |
| Caught by both | 1,001 |
| Total unique credentials | 26,400 |
Either scanner alone would have caught only about half of these credentials; the two tools' detector coverage was largely complementary. TruffleHog dominated Alibaba Cloud key detection (9,428 vs. 993), while Kingfisher dominated DeepSeek (2,940 vs. 230), OpenAI (1,198 vs. 150), HuggingFace (154 vs. 1), and Chinese-AI services like Zhipu (1,489 vs. 0) that TruffleHog has no detector for.
The single most common leaked credential type was Alibaba Cloud AccessKey pairs: roughly 1 in every 766 Gitee repositories contained a verified-live Alibaba Cloud credential. A long tail of additional vendors — LangSmith, OpenWeather, Algolia, PostHog, OpenRouter, MySQL, Stripe, Slack, Twitter, and others — accounts for the rest.
Figure 2. Credentials by vendor.

The vast majority of verified-live credentials were committed in the last two years, with 2025 alone accounting for 12,242 unique credentials, nearly half the entire dataset.
Figure 3. Unique credentials committed by year.

Most credentials were committed from personal mail services (qq.com, 163.com, gmail.com), making per-company attribution impossible at scale. The corporate-domain numbers are therefore a floor, and even that floor spans major Chinese and Western technology companies — the breadth includes Huawei, ByteDance, Google, Microsoft, Oracle, and others — alongside smaller footprints from Apple, Meta, Anthropic, plus Chinese commercial and academic domains.
Figure 5. Unique credentials by committer email domain.

The closest prior data points come from TruffleSecurity's scan of 5.6 million public GitLab repositories , and a companion Bitbucket scan referenced in that post.
| Platform | Repos scanned | Verified-live credentials | Per 1K repos |
|---|---|---|---|
| Bitbucket | ~2,600,000 | 6,212 | 2.39 |
| GitLab | ~5,600,000 | 17,430 | 3.11 |
| Gitee | 7,256,531 | 26,400 | 3.64 |
Gitee tops both Western platforms on raw count and on per-repository density. One methodology note before you quote these numbers: the TruffleSecurity scans used TruffleHog alone, while this one used TruffleHog and Kingfisher together. TruffleHog's detector library skews toward Western vendors, and Gitee has heavy Chinese-vendor activity (Alibaba Cloud, DeepSeek, Zhipu, and others) that Kingfisher's coverage helps to surface; stripping the findings to TruffleHog-only puts Gitee at 1.76 per 1,000 repos.
Vendors with the highest exposure volume in this scan were emailed a coordinated report containing the full list of verified-live credentials associated with their service, along with source-repository metadata to help them attribute affected customers. Per-developer notification — contacting the committer of each leaked credential individually — was not pursued at this scale, because vendor-side revocation is the more reliable path and does not require any action from the user who leaked the credential. At the time of writing, revocation status for the disclosed credentials has not yet been confirmed.
26,400 unique verified-live credentials across 7,256,531 public repositories — the 7.25 Million repository figure that frames the study — deduplicated by raw secret value after both TruffleHog and Kingfisher authenticated candidates against vendor APIs.
Detector coverage was complementary. TruffleHog led on Alibaba Cloud (9,428 vs. 993), while Kingfisher led on DeepSeek (2,940 vs. 230), OpenAI (1,198 vs. 150), HuggingFace (154 vs. 1) and Zhipu (1,489 vs. 0), where TruffleHog has no detector at all.
On published density, yes: 3.64 per 1K repositories against 3.11 for GitLab (~5,600,000 repos, 17,430 credentials) and 2.39 for Bitbucket (~2,600,000 repos, 6,212 credentials). Normalise the tooling by using TruffleHog only, however, and Gitee reads 1.76 per 1,000 repos — compare like-for-like before drawing conclusions.
Not confirmed. Reports went to the highest-volume vendors with repository metadata for customer attribution, but revocation status for the disclosed credentials had not been confirmed at the time of writing.
Yes. The Modal + dual-scanner architecture runs against most Git hosts with little more than a clone-URL substitution, cost roughly $3,000 end to end, and was previously used at smaller scale in an investigation of Algolia DocSearch admin keys.
Gitee is now a measurable credential-exposure surface rather than an unknown: higher per-repository density than comparable published scans of GitLab and Bitbucket, a committer population that spans every major vendor's workforce, and an asymmetric remediation landscape where disclosure often has nowhere to land. None of that requires exotic tooling to detect — two open-source scanners, one Python script and about a month of compute were sufficient. Teams that run the same checks against their own repositories, on their own schedule, will always learn the number before an attacker does. Questions on this analysis or on hardening Git-side secret detection for your environment are welcome at the IT Insights security desk, contact@itinsights.com .