{"id":50074,"date":"2026-11-10T18:43:17","date_gmt":"2026-11-10T13:13:17","guid":{"rendered":"https:\/\/www.getastra.com\/blog\/?p=50074"},"modified":"2026-11-10T18:43:20","modified_gmt":"2026-11-10T13:13:20","slug":"github-secrets-exposed","status":"publish","type":"post","link":"https:\/\/www.getastra.com\/blog\/security-advisory\/github-secrets-exposed\/","title":{"rendered":"How Easy Is It to Get Secrets From GitHub?\u00a0"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\"><strong>TLDR<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A GitHub code search for the AWS access key pattern \/<code>AKIA[0-9A-Z]{16}\/<\/code> returns almost <strong>500,000 <\/strong>results from an authenticated session. If even 1% are live, that is roughly <strong>5,000 <\/strong>working keys.<\/li>\n\n\n\n<li><a href=\"https:\/\/blog.gitguardian.com\/the-state-of-secrets-sprawl-2026-pr\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">GitGuardian\u2019s 2026 State of Secrets Sprawl report<\/a> counted <strong>28.65 million<\/strong> new hardcoded secrets added to public GitHub in 2025, a <strong>34<\/strong>% year-over-year jump. AI-assisted commits leak at twice the baseline.<\/li>\n\n\n\n<li>Deleting the commit does not delete the secret. <a href=\"https:\/\/trufflesecurity.com\/blog\/anyone-can-access-deleted-and-private-repo-data-github\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Truffle Security\u2019s CFOR research<\/a> showed 4-character SHA-1 brute-force is enough to recover secrets from deleted forks and private repos.<\/li>\n\n\n\n<li><a href=\"https:\/\/securityledger.com\/2026\/03\/exposed-developer-secrets-surge-ai-drives-34-increase-in-2025\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">64% of credentials flagged as exposed in 2022 were still valid in early 2026<\/a>. The leak is not the end of the problem. The decision not to rotate is.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Every engineer reading this has at least once committed a secret by accident, noticed within the hour, force-pushed the fix, and gone back to work slightly embarrassed. The dangerous part is that the \u201cfix\u201d we all learned from the first Stack Overflow answer we googled does almost nothing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The next 1,500 words are about why deleting a leaked secret is theatre, how easily attackers find the ones we did not catch, and what posture actually bounds the damage when a credential do<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Okay_just_one_search\"><\/span>Okay, just one search<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">GitHub\u2019s code search accepts regex if you are signed in. So I tried a single query against the AWS access key format:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>\/AKIA[0-9A-Z]{16}\/<\/code><\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1403\" height=\"584\" src=\"\/cdn-cgi\/image\/quality=80,format=auto,onerror=redirect,metadata=none\/https:\/\/cdn-blog.getastra.com\/2026\/11\/feee7925-image.png\" alt=\"\" class=\"wp-image-50075\" style=\"aspect-ratio:2.4;width:624px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Almost<strong> 500,000 results<\/strong>. Half a million. Lol.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s assume only <strong>1%<\/strong> are live, and the rest are honeytokens, test fixtures, documentation examples, or keys already revoked by GitHub\u2019s or vendors\u2019 scanning pipelines. That is still roughly <strong>five thousand working AWS keys<\/strong>, publicly addressable through two clicks and a regex, by anyone with a free GitHub account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As a threat actor, the damage I could do with one of these is generous. I could disable GuardDuty findings before the SOC sees them, or spin up crypto mining rigs on someone else\u2019s bill.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The economics have never been this favourable for the attacker side, and this is before I talk about Stripe <code>(sk_live_),<\/code> OpenAI <code>(sk-proj-)<\/code>, Anthropic <code>(sk-ant-api03-)<\/code>, Slack (<code>xoxb-)<\/code>, GCP service accounts<code> (JSON with a private_key field<\/code>), and GitHub\u2019s own personal access tokens <code>(ghp_)<\/code>, which are, somewhat embarrassingly for GitHub, also sitting in the result list.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"So_can_you_delete_it\"><\/span>So can you delete it?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Yes, but it does not save you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Devs who notice a leaked secret usually remove it in the next commit and move on. That removes the file from the working tree. It does not remove the commit from the git object graph. The old commit still exists in the repo\u2019s .git\/objects\/pack store, reachable by its SHA-1, until a git gc pass eventually prunes dangling objects. On a public repo, that window is days to weeks. Any crawler that captured the commit before the garbage-collection sweep still has it. GitHub\u2019s documentation now explicitly treats a pushed secret as compromised the moment it hits a public repo. Rotating is the actual defence. Deleting the commit is theatre.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Forks make deletion worse. GitHub stores all forks of a repository in a shared object network. Every fork sees every commit\u2019s object, regardless of which branch references it or whether the branch still exists. Truffle Security published the attack in 2024 and coined the term Cross Fork Object Reference (CFOR).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then there is everything outside the code. 28% of secret leak incidents in 2025 originated outside source control entirely, in Slack, Jira, Confluence, internal wikis, and the collaboration surface that now includes AI assistant chat logs. A credential screenshotted into a Jira ticket at 2 a.m. carries the same blast radius as one committed to main. The screenshot is arguably worse, because most secret scanners do not OCR images by default.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Best of all, none of it rotates. Of the credentials GitGuardian originally flagged as exposed in 2022, 64% were still valid and exploitable as of early 2026. Secrets have grown 152% since 2021 while the active dev base grew only 98%. Much like most security problems today, this one is also accelerating faster than the people available to fix it.<br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"So_how_do_you_actually_delete_it_properly\"><\/span>So how do you actually delete it properly?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u201cYou revoke it.\u201d Period. Treat \u201cdeletion\u201d as a wrapper around rotation, not an alternative to it. The order of operations that actually works:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Revoke the credential at the source first.<\/strong><\/li>\n\n\n\n<li><strong>Issue a replacement credential with the narrowest scope the app actually needs.<\/strong>\u00a0<\/li>\n\n\n\n<li><strong>Rotate every downstream system that consumed the old credential.<\/strong><\/li>\n\n\n\n<li><strong>Only then, clean the git history.<\/strong> <code>git filter-repo <\/code>or <code>BFG Repo-Cleane<\/code>r to rewrite the history. Ask GitHub Support to purge the cached views. Contact fork owners if the repo has any. (Note: None of this makes the credential safe. It only makes the repo cleaner.)<\/li>\n\n\n\n<li><strong>Monitor for use of the old credential for 90 days.<\/strong><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Need a scanner first?<\/strong> Before the rotation runbook and the blast-radius posture, your detection layer has to actually work. Start here: <a href=\"https:\/\/www.getastra.com\/blog\/cloud\/secret-scanning-tools\/\" target=\"_blank\" rel=\"noreferrer noopener\">the secret scanning tools worth evaluating in 2026<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Final_Thoughts\"><\/span>Final Thoughts<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Assume secrets will leak, and design the response for the day one does.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Detection is the baseline, and our secret scanning covers it across repos, CI, IaC, and the collaboration tools where more than a quarter of incidents originate. But detection alone does not stop a leaked key from becoming an incident. Continuous pentesting does.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Continuous pentesting combined with periodic red teaming shrinks the space an attacker can operate in if they exploit a leaked key or try to move laterally from it.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At Astra, we offer red teaming, plus continuous DAST and autonomous pentesting. Together, they match your deployment cadence rather than your fiscal year.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.getastra.com\/schedule-a-demo\" target=\"_blank\" rel=\"noreferrer noopener\">Book a demo<\/a>. Do not wait for the leak to be yours.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TLDR Every engineer reading this has at least once committed a secret by accident, noticed within the hour, force-pushed the fix, and gone back to work slightly embarrassed. The dangerous part is that the \u201cfix\u201d we all learned from the first Stack Overflow answer we googled does almost nothing. The next 1,500 words are about &#8230; <a title=\"How Easy Is It to Get Secrets From GitHub?\u00a0\" class=\"read-more\" href=\"https:\/\/www.getastra.com\/blog\/security-advisory\/github-secrets-exposed\/\" aria-label=\"Read more about How Easy Is It to Get Secrets From GitHub?\u00a0\">Read more<\/a><\/p>\n","protected":false},"author":138,"featured_media":50076,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[819],"tags":[],"class_list":["post-50074","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security-advisory"],"_links":{"self":[{"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/posts\/50074","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/users\/138"}],"replies":[{"embeddable":true,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/comments?post=50074"}],"version-history":[{"count":1,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/posts\/50074\/revisions"}],"predecessor-version":[{"id":50077,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/posts\/50074\/revisions\/50077"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/media\/50076"}],"wp:attachment":[{"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/media?parent=50074"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/categories?post=50074"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.getastra.com\/blog\/wp-json\/wp\/v2\/tags?post=50074"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}