November 3, 2026
How a Single Leaked Client Secret Exposed a Private GitHub Repo
From a hardcoded credential in a JavaScript bundle to full admin access: A case study in exploit chaining.

By Prosper Kalu
2 min read
During a recent assessment, I turned a single hardcoded secret found in a public JavaScript bundle into administrative access to the target's private GitHub repository. The chain took four unauthenticated steps:
hardcoded OAuth app secret (public JS)
โ mint an app access token
โ enumerate webhook callback URLs (internal hosts leak)
โ hit a leaked webhook โ production debug page
โ git remote in the debug page contains an admin-scoped GitHub PAThardcoded OAuth app secret (public JS)
โ mint an app access token
โ enumerate webhook callback URLs (internal hosts leak)
โ hit a leaked webhook โ production debug page
โ git remote in the debug page contains an admin-scoped GitHub PAT
No user interaction, no victim, no privileged account. Just the public bundle.
The starting point: a secret that should never be in the browser
The app's frontend bundle shipped an OAuth App Secret in plaintext. Secrets like this are server-only by definition โ the browser can't use them without exposing them.
curl -s "https://graph.example.com/oauth/access_token?client_id=REDACTED&client_secret=REDACTED&grant_type=client_credentials"
# {"access_token":"REDACTED|โฆ","token_type":"bearer"}curl -s "https://graph.example.com/oauth/access_token?client_id=REDACTED&client_secret=REDACTED&grant_type=client_credentials"
# {"access_token":"REDACTED|โฆ","token_type":"bearer"}Step 1 done. I now had a valid app token โ authenticated as the company's own application. โ -
Step 2: the secret maps out internal infrastructure
App tokens are supposed to be low-value. But with this one, the provider's API happily returned the app's webhook subscriptions โ including internal callback URLs:
Step 3: a leaked webhook exposes a production debug page
One of the webhook URLs returned an HTTP 500 with a full laravel framework debug page when hit with a plain GET.
debug: true,env: production- framework and language versions
- full filesystem paths
- a git commit hash and commit message Debug mode in production is a classic finding on its own. But the page had something worse hidden in it
Step 4: the debug page leaks an admin GitHub token
Framework debug pages often embed a JSON "report" with app metadata โ including the deployed app's git remote URL. In this case, the remote had a Personal Access Token baked into it:
Validation (metadata-only)
I confirmed the token without touching source code:
Impact
- Source disclosure โ full read of the private backend.
- Supply-chain risk โ push access allows code tampering.
- Secrets exfiltration โ CI/deploy secrets readable by an admin token.
- Infrastructure mapping โ webhook URLs + admin IDs leaked earlier in the chain.
Why this happened (root causes)
- Hardcoded secrets in the client โ the OAuth secret should live server-side, behind a proxy/BFF.
- Debug mode in production โ
debug: truerendered stack traces and app metadata to the public. - Token in the git remote โ a PAT embedded in the repo's remote URL, which then leaked through error reporting. Each one is a common mistake. Chained together, they produced a Critical. โ -
Disclosure
This was found during authorized testing. I validated the token with metadata-only API calls โ no source code was read or modified โ and the organization revoked the token and rotated their secrets after disclosure.