← All talks

Nintendon't Look at my GitHub: DMCA Dodging and Other Shenanigans

BSides PDX 202520:5487 viewsPublished 2025-12Watch on YouTube ↗
Speakers
Tags
CategoryTechnical
StyleTalk
About this talk
James Martindale explores GitHub's implementation quirks that enable unconventional repository manipulation: recovering commits from deleted projects, restoring hidden commit history, and exploiting fork architecture to evade DMCA takedowns. The talk covers real-world examples including Wapalyzer recovery, a Yuzu emulator takedown response, and techniques for hiding arbitrary content in public repositories through commit spoofing.
Show original YouTube description
Nintendon't Look at my GitHub: DMCA Dodging and Other Shenanigans - James Martindale GitHub forks are...weird. A couple implementation quirks lead to some funny (or alternatively, scary) consequences. And yeah, this is publicly documented, but who reads these days? This talk walks through real-world personal examples: recovering commits from a deleted project, brute forcing hidden commit history back into existence, and skirting a DMCA takedown by inserting hidden commits in a someone else's repository. James is a web/cloud penetration tester at Anvil Secure, based in Seattle. His research interests include API security, hardware hacking, and abuse cases. He spends too much of his free time in Grand Theft Auto Online, where the hacking minigames are much easier than his day job. --- BSides Portland is a tax-exempt charitable 501(c)(3) organization founded with the mission to cultivate the Pacific Northwest information security and hacking community by creating local inclusive opportunities for learning, networking, collaboration, and teaching. bsidespdx.org
Show transcript [en]

[music]

[music] Hope you're all having a good conference so far. So yeah, my name is James. I work for a pen testing firm up in Seattle called Amble Secure. That's the uh slide design. And I guess that's really all you need to know about me. Uh I have a lot of material and I tend to kind of talk fast. So, if you want to find the slides to follow along, you can check the talk details in the Bside schedule page. But this talk is about a couple run-ins with the DMCA uh and a few other stories that all revolve around a couple implementation quirks in GitHub. And since this is a besides audience, you probably know what GitHub is, but I

mean, you never know for sure. So, in case you need it, uh Git is a version control system for text files. So you put these files in a special folder called a repository. And each version you make is called a commit. It has a cryptographic hash instead of a version number. And this is really helpful uh for various reasons. And one of the reasons is you can have multiple branches of history. And that's really helpful for you have like one product and different teams working on different features. Uh they can work on their own stuff without having to constantly sync with each other or stepping on each other's toes. Once they're done with their work, they can merge into the

default branch. And yeah, that's git. GitHub is probably the most popular uh place to host Git repositories. Anyone can view or download a public repository. And only authorized users can push commits to an a repository. That's you and anyone you authorize. So if you want to suggest changes to a repository you're not in, uh you click that fork button which makes a copy in your account. Uh and it has a link back to the original as you can see in the top left uh to the upstream as as we call it. And you make your commits in your fork. uh you submit a pull request to say, "Hey, merging my changes." And yeah, that's how it goes. So, if you

needed that, that hopefully that was helpful. And for everyone else, you uh cut the part where I lied, right? Cuz it turns out the fork button does not make a copy. Uh cuz GitHub forks are all the same repo as the upstream. They they all share the same objects and stuff. And of course, you already knew that because GitHub has this documented and everyone reads the docs. And if you were here for the uh previous talk about TJ actions, they did touch on this a little bit. This is I'm not going to talk about CI/CD stuff so much, but it's the same stuff under the hood. But yeah, this might be a bit to wrap your head around

if you haven't seen this before. So, I'll start simple with the first time I ever I guess messed around with this feature. Uh there was this tool called Wapalyzer. It's still around. It's just a little bit different now. Uh it's a website browser extension that tells you what tech a site is built in. And this is really helpful for pen testing cuz you might want to find some low hanging fruit like hey update engine X or you've got a jQuery version somehow still that has known vulnerabilities in it and you can see if it's exploitable. So something that was really cool about is that it had local detection rules that ran in your browser. Uh and so that

meant you didn't have to wait for a scraper to come by and update a site. you could run it live and it also would check like it ran in your browser so you can check non-public sites like UAT sites or internal sites stuff like that. It was probably the second tools introduced to after burpuite. I found it really helpful at my first uh pentesting job but uh eventually just my the nature of my work changed. I changed jobs and I didn't need to use it for a while. So I ignored it for a while but then a few years later I finally had an engagement where it made sense to try to use Walizer. So, I went to the GitHub repo

for it and was going to download it, but uh I guess it was gone for some reason. And it turns out that the author deleted the Walizer repository and this was kind of sad, but I get it. I mean, corporations, they see open source code and they're like, "Hippity hoppity, that code's not my property." And he was trying to, you know, this was kind of a solo gig. I mean, it was open source, so there were contributions, but he was writing most of the code. He was trying to monetize it with his own paid service, but he was basically working for free to make his competitors better. Yeah, I can see why he wanted to delete

it, but it would have been nice to at least keep up like all the historical commit history cuz sure, remove your commits, but I actually contributed a few rules. What about my commits? Well, okay, what about my commits? Cuz if I made contributions, I probably had a fork and I never deleted it. It's still there. It's just a bit out of date. You can see that's the last commit was from 3 years ago. So, at least I had what I wrote, but I thought it'd be nice to have everything up to the point where Wapalizer got deleted. Uh, and so I already knew that in theory, this is my fork is the same repository as the

original Wapalizer repo. So, if I can just find the commit hash, the last one that was published before it got deleted, then that should exist in my repo somewhere. Uh, so to find that commit hash, there's this cool website you've never heard of before called archive.org, and you can just put in the URL and yeah, there we go. We got a commit hash uh in red and then going to my fork. That's the most recent commit in blue. Uh at the top, that is the URL to see the state of my repo at my latest commit. And then all I have to do is just swap out that commit hash for the webizer commit hash. And there we go.

That's not me. That is the original authoralizer. So there we go. We've got the code for weapilizer except uh you know that URL at the bottom is kind of long. I don't want to have to bookmark it. And normally when you work with git repos, you clone them to your computer. And if I clone this, it's not going to have this uh commit hash. So what can I do about that? Let's talk a bit more about git branches. Cuz branches, while they are, I guess, logically a list of commits, they're not actually a list of commits cuz each commit knows which commit came before it. And so a branch just needs to have a pointer to the most

recent commit in the branch. And then you just check the one before that, the one before that, etc. You have the whole history. And then whenever you make a new commit, it just pushes the head of that branch up one. So what I want to do is I want to take my commit hash from down there and just go forward in history and see if I can sync it up with walizer. And that's actually super straightforward. So I have to clone uh my fork of the repo. And then when you do a clone, it's only going to give you the hashes that are part of the branches in your fork view of the repository. So

I had to explicitly ask the GitHub server for the full commit hash uh that I found earlier cuz it didn't push it during the clone. And then I can just turn around and say, "Okay, get push origin set this commit to be the head of master." And there we go. I go to just my fork page and it's there. That's all the up-to-date wopilizer code. I mean obviously it's been a few years so it's now 2 years ago instead of 3 years ago but uh you know this is practical. I really got some use out of this. Um but there's more fun you can do with uh this property and I did kind of promised

something in the title of my talk. So let's talk about Nintendo. You know who they are. You probably know they are very ligious. [sighs] Uh you may have you may have caught some headlines last year about two high-profile takedowns of Switch emulators. Uh, this will talk about Yuzu, which was the one that happened earlier in the year, and that's what these headlines are about. Uh, and when I saw these news articles, I thought, okay, I mean, that's sad. I kind of care about game preservation, but I don't play Switch games, so it didn't matter to me so much. Uh, but I completely forgot. I I'll blame it on ADHD, I guess. I I actually had a Forka Yuzu

just sitting around. Um, I don't know why. I never contributed anything, but it just sat there. And so, uh, surprise surprise, I got an email from GitHub. They're like, "Hey, we got a DMCA takedown notice for your repo." And I thought, "Okay, that's fine." Uh, I was just going to delete it. But it turns out that if I looked at the email again, they actually said that I could make requested changes. And I was like, "Okay, well, what would requested changes be?" Um, you know, the the walizer thing I did, I basically took a commit down here and pushed it up forward in history. What if I just, you know, did the reverse and reround

history to the first commit ever? Cuz then I would just have like a readme file and nothing else and there technically wouldn't be any emulation code in there. Uh, so why not try that, right? Just to find the first commit, I run get log- reverse. I get a commit hash and then I do the same command as before. Basically, just I give it the commit hash col. I have to add this d-force because normally git will say this is a terrible idea. Why do you want to do this? And because it's theoretically a destructive action. Uh so yeah, I do that do a push and I go to my fork and there we go. There's just a read me, nothing else. Uh

but I I did have to check I did have the commit hash from earlier. So I just I checked the URL for that and it the code was still in there. Um but I can't do anything about that. I did the best I could and I mean GitHub is going to know what I did, but I I pretended I didn't know that. I just said, "Hey, as requested, the repository no longer has any commits. Reference Nintendo hardware or software." Um, and they said, "Okay, thanks for letting us know. We will reach up when we're done." And so, this was a long 24 hours just kind of like, "They're going to figure this out." But no, they they said, you know, thanks

for letting us know you made changes. Um, and so I was patting myself on the back like, I can't believe I pulled a fast one on GitHub. That's that's really cool. Uh, and so yeah, that's how the story ends is basically they uh they went to Nintendo and they're like, "Hey, James made changes." And Nintendo's like, "Okay, yeah, so we need to delete Yuzu and every single fork. Actually, all the forks, but James' cuz just James' is fine." No, they they I don't know why I thought they would care, but uh you know uh I didn't actually show you the DMCA takedown notices, just some of the emails. And I don't have to uh because in the interest

of transparency, GitHub publishes all the DMCA notices and counter notices that they receive and they put it all up in a central uh place for the public to see. You might call it a repository. It has a fork button. [laughter] May maybe you see where this is going. Um [laughter] cuz my manager did and he was like, "Hey, please stop." Uh, [snorts] and you know, at first I thought like, okay, man, let me have some fun. Like, this is, but I mean, I I had to check. Um, [snorts] turns out Nintendo, their office, you can drive to my desk within 30 minutes. So, maybe I don't want to poke the bear, right? Um, so I I'll make

it up to you, right? I did promise some DMCA shenanigans. So, let's talk let's go back a few more years. Uh, in 2020, the RAA submitted a takedown, uh, notice for YouTubeDL, uh, which is a tool. You probably know what it does. It downloads stuff from YouTube and other sites. Uh, and they alleged that it was bypassing copy protection, which is not true, but, uh, GitHub legally had to comply, and that was not a very popular move, but they had to. Um, and so there were lots of discourse on Twitter, etc. about that, but uh some maverick out there decided to take it upon themselves to push the entirety of YouTube DL's commit history to the DMCA repo,

which is probably the funniest possible reaction you can have to a DMCA takedown. Pretty based. Uh now, a month later, GitHub did reinstate the repository and they even made a big old blog post about it saying like, "Yes, we're standing up for developers. We have a whole new process to evaluate uh DMCA takedowns based on circumvention. Um they even like announced a legal defense fund and that's cool. But more importantly uh that means I can replicate their work and it won't be breaking IP law. So how do you do that? Uh it's again really simple. You just assuming you already forked the DMCA repo. You just and you also have a copy YouTubedL. You just change the remote

URL and you push. You have to use D-force again. And there you go. There's YouTube DL in my fork of the DMC repo, but you know, you start with the commit hash URL, swap out the username, and there we go. It's it's in GitHubs. Now, of course, I, you know, I was done with this, so I figured I might as well delete my fork, and it's still there. I can't get rid of it. Um, cuz it turns out the deleted commits aren't just delete, aren't deleted, they just get hidden. And so, this is kind of like a tool for bulletproof file hosting, maybe. Like, I didn't have to upload legal source code. This could have been

switch emulation code. This could have been anything. This could have been really any public repository. Um, you can hide any as long as you're okay with having to find the commit hash or just link it. You can hide anything you want in any public repository. Um, as anyone cuz of commit authorship cuz commits all have an author name and email address. You can view this uh in git or uh in GitHub. You can add that patch to the URL to see it. And even for users that don't have a commit, you can there's this default user that or this default email address you can use. And GitHub will match users to commits by email address and you can pick whatever you

like. So um my name is Lenus Torvaltz and that's my email address. And Lenus uh made a commit in the WSL repo where he removed all the bad code. And just to clarify that is that is his actual GitHub account. Um not not a fake one. And I mean I've got another story for you. Did you know that Tim Sweeney of Epic Games accidentally committed a Fortnite V-Bucks generator to an Epic Games repository? It's definitely not malware. Um, you should you should definitely try it. Uh, got another story for you actually. So, Vog Bdderin of Ethereum fame actually add this little uh Easter egg into an Ethereum uh repository and you know that it's actually him because this

repository is archived. So, I didn't just commit this last night. You know, if just to say like, hey, thanks for exploring the code. uh click on this link for a small reward. It's definitely not a fishing link. Yeah, I think fishing is an opportunity possibly here. I don't know if it would work for a general audience, but maybe it would do well in certain verticals where people think they know computers but really don't. So like gaming, blockchain, vibe coding, that kind of a thing. But uh how do you find these commit hashes, right? Like how do you see like what stuff people have hidden in places? uh you you can't really brute force these hashes

because they're they're really long and that would take forever and GitHub would ban you before you even got close. Uh but a fun fact about Git and GitHub, uh they also support this thing called short hashes where as long as you provide enough characters that no other commit starts with those characters, uh it'll just figure it out for you. And you can indeed brute force four alpha numeric characters. It's not that bad. Uh, and the secret scanner tool, Truffle Hog, has a built-in mode to do this. Um, but, uh, to try this out, we need an example. So, if you work for AMD, please don't hurt me. Um, back in August, they accidentally committed some confidential

source code to one of their open source repos, and they went ahead and they did the right thing. They rewrote history to remove those commits. Um, but as we know, commits don't get deleted. So, to find that you, it's actually pretty straightforward using truffle hog. There's a GitHub experimental subcomand. You run it out of discovery mode. You give it the repo and it's you just let it run. Uh it brute forces short hashes and tries to find the long ones. Um the time depends on how many commits are in the repo. And for Fidelity FX SDK specifically, for some reason there's only like seven public commits, but AMD rewrites the hell out of their history.

And so a full scan takes like 200 hours. Um, but I got super lucky uh because truffle hog as it works through this list. It will build out this text file that shows you the hash it's found so far. And would you believe that the hash I was looking for was number three in the list. So it only took like a few hours and there we go. That little internal folder you see is how you know this is internal confidential proprietary source code. Um, and they can't do anything about it. It's just there forever. Uh, I don't know what to tell you. Uh now everything I've shown you so far you can reproduce. Uh except

for this and that's just because truffle hog is a little bit too smart. Uh audit discovery mode doesn't flag commits that normal mode can find. It makes sense because brute forcing is super expensive. Uh and truffle hog can actually scan pull requests. It's one of the cool things it can do. And the reason why it can do this is because GitLab and GitHub actually publish uh refs for the pull requests. You can look at a whole list of refs by just running get ls- remote. That's an example right there. Uh, and so if any commit is in a pull request, auto discovery mode won't flag it and you can't find that commit through autodiscocovery mode because

someone thought it would be funny if they made a pull request to add the commit back in. So I guess moral of the story is if you're looking for secrets and and you know juicy information, right? Like API keys you can revoke, you can't really revoke source code. Uh, you should definitely check the poll request before anything else. Uh, I guess I have that in there just to point out that that's not their commit. Uh, so in summary, uh, two quirks. GitHub forks are all the same repository as the upstream. And GitHub doesn't delete commits. So some shenanigans you can do with that. You can make hidden commits anywhere as anyone. You can do that for

piracy trolling malware fishing more creative things like CI/CD compromises, I guess. Uh, you can also find deleted commits and secrets by brute forcing short hashes. Uh, so some takeaways I guess is you might want to check your threat model cuz if the risk of you accidentally committing something that you cannot remove without nuking your repo and every other fork of it. If that's not something if that's not a risk you can accept, you may want to reconsider using GitHub. And definitely uh I've heard of people using this trick for bug bounties and stuff. So you know have at it but have fun responsibly. Uh I am not over time. That's cool. Anyway, I will open the floor to questions.

>> [applause]

[applause] >> Do you know if you delete your account your commits will go away? >> My understand Oh. So what would happen is it would delete your repository and if a repository gets deleted the the upstream repository is the oldest fork. So no. Do other Git forges behave in the same way or is this specifically a GitHub quirk? >> From what I can tell, this is I I wanted to look, but I ran out of time because of ADHD, but I'm assuming it's just a GitHub specific thing cuz uh Trouble Security, this is something that's been publicly known. Trouble Security wrote a few blog posts about it, and I feel like a security team trying to give this a

whole scary uh vulnerability class name would try to see if it works with other Git forges as well. So, I'm assuming it doesn't. Uh maybe that's something to check to double check. >> So I was under the impression and maybe uh you just proved this wrong that GitHub support could if you had GitHub enterprise actually fully delete a commit from history. Uh but is that just fundamentally not possible? >> I was hoping wouldn't ask that question. So technically it should be feasible. Git itself has tools to do that. Um I've just in practice I've never ever seen it. Uh I don't know if that's something specific to enterprise or not. I guess really the thing is like I've never seen

it happen and so if you wanted to just throw up some illegal file somewhere in someone's repo like it's not going to get removed unless someone happens to find it and pisses off Nintendo or GitHub enough. But yeah, >> how likely do you think it is that GitHub will find this video and try to take it down in some way? >> Um >> like fix the solution the repository. >> I think they should fix it. I think this is something that I understand why they do it, but I think it has some unintended consequences. I would like to say I would never do a cyber crime. So, just just so you know, um I I think this

is this isn't that they they document and it's something that's been covered so many times. They've probably gotten a million duplicates to the bug bounty because of this. So, this is something that they've they're either stuck with or they've doubled down on. So, I don't think this will change anytime soon, but please GitHub, if you see this, prove me wrong. I mean it is fun to play with but still it's >> going once going twice. Sold to James. Your time is given back. [applause] Thank you James. [music]