{"slug": "ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-all-30", "title": "GhostAction now scans your git history for secrets. I deleted 30 keys and recovered all 30.", "summary": "A developer built a test repository with 30 planted AWS credential pairs and 30 GitHub tokens to measure how thoroughly the GhostAction supply-chain campaign's new git-history secret scan recovers secrets that were committed and later deleted. A HEAD-only scan recovered 0 of 30 keys and tokens, while a `git log -p --all` history scan with simple regexes recovered all 30 of each in roughly 9 milliseconds across 52 commits, with the deletion commit appearing as a second copy of each secret. GitGuardian reported the October wave compromised about 1,900 GitHub accounts, attempted extraction of 3,174 secrets, and deployed the payload to roughly 28,000 new repositories.", "body_md": "The newest wave of GhostAction — the supply-chain campaign that pushes a fake \"security audit\" GitHub Actions workflow into repositories using stolen maintainer credentials — added a feature that should change how you think about every secret you have ever committed.\n\nGitGuardian's reporting on the October wave is specific about the payload's evolution. Version one of the new payload added a **git history secret scan**: regular expressions over your history for AWS key IDs, GitHub and GitLab tokens, AI-provider keys and other cloud credentials. Version two added context capture — about two lines around each AWS key ID, so the ID can be paired with its matching secret access key. Version three brought that context capture to the history scan too.\n\nThe scale, per GitGuardian via The Hacker News (October 15): about 1,900 GitHub accounts compromised in the October 8–9 spike, extraction attempted for 3,174 secrets, and the payload deployed first to 160 previously observed victims and then, 20 minutes later, to about 28,000 new repositories.\n\nI wanted to know two things about that history scan. How complete is it against the one remediation everyone actually does — \"I committed a key, then I deleted it\"? And how well does the two-line pairing trick actually work?\n\nSo I built a repo where I know the ground truth, because I planted it.\n\nI created a repository and planted 30 AWS credential pairs plus 30 GitHub tokens, in plain config files, at controlled line distances between the key ID and its secret — 0, 1, 2, 3, 5 and 10 lines apart, five pairs at each distance. Then 20 boring documentation commits, then a file of lookalikes (including `AKIAIOSFODNN7EXAMPLE`, the example key from AWS's own docs). Then the commit everyone trusts:\n\n``` bash\n$ git log --oneline | head -3\n... remove leaked keys\n... add examples\n... docs 19\n\ncommits total: 52\nconfig files remaining at HEAD: none\n```\n\nEvery secret file deleted. Working tree clean. If you scanned this repository the way most people scan — current files only — here is what you get:\n\n```\n[HEAD-only scan]\n  real AWS IDs recovered:    0 / 30\n  GitHub tokens recovered:   0 / 30\n  secret keys recovered:     0 / 30\n  raw ID hits: 2 — both lookalikes in examples.txt, including the AWS docs example\n```\n\nClean. Also, completely meaningless.\n\nThe entire history scan the payload needs is one command any CI runner can already execute, and one regex pass:\n\n```\ngit log -p --all\nPAT_ID  = re.compile(r\"AKIA[0-9A-Z]{16}\")\nPAT_TOK = re.compile(r\"ghp_[A-Za-z0-9]{36}\")\nPAT_SEC = re.compile(r\"aws_secret_access_key\\s*=\\s*([A-Za-z0-9+/]{40})\")\n```\n\nAgainst my \"remediated\" repository:\n\n```\n[history scan: git log -p --all]\n  dump size:        39,406 characters, 1,642 lines, 52 commits\n  time to dump:     ~9 ms\n  real AWS IDs recovered:       30 / 30\n  GitHub tokens recovered:      30 / 30\n  secret keys recovered:        30 / 30\n  raw regex hits: 62 IDs, 60 tokens, 60 secrets\n```\n\n30 out of 30. All of them. The raw hits are roughly double the planted count because `git log -p` shows each secret twice in this repo — once in the commit that added it, once in the diff of the commit that \"removed\" it. The deletion commit is not a cleanup in the history; it is a second copy.\n\nAnd the cost is the point. A 52-commit history dumps in about 9 milliseconds on this machine, and the regex pass over it is sub-millisecond. Scanning history instead of HEAD is not a more expensive attack. It is the same attack with a longer flag. Multiply a few milliseconds by 28,000 repositories and the history feature costs the campaign essentially nothing — which is presumably why it exists.\n\nAn AWS key ID alone does not authenticate anything. The attacker needs the secret access key that goes with it, and that is what payload version two's two-line context window is for. On my planted pairs, that window has a hard edge:\n\n```\nplanted distance      paired within ±2 lines\n(ID line → secret)    \n  0 lines (same line)     5 / 5\n  1 line                    5 / 5\n  2 lines                   5 / 5\n  3 lines                   0 / 5\n  5 lines                   0 / 5\n 10 lines                   0 / 5\ntotal paired: 15 / 30\n```\n\nEvery pair whose secret sat within two lines of its ID got paired. Every pair further away did not — even though the secret was sitting right there in the same dump, recoverable by label, waiting for a smarter matcher. My distances are synthetic, and real `.env` files usually do keep the two values adjacent, which cuts in the attacker's favour. But the 15/30 split explains the payload's own changelog better than any write-up did: version two exists because IDs without secrets are inventory, not access — and version three exists because the first place pairing had to work was history, where the good stuff is.\n\nIt also explains the defence that follows from it. Format does not save you — a secret 10 lines from its ID defeated a two-line window in my test and would not defeat the next version of the payload, or a human. The only version of \"I deleted the key\" that means anything is \"I deleted the key **and rotated it**.\" Deletion changes what HEAD shows. Rotation changes what the history is worth. Only one of those is a remediation.\n\nOne more honest note from the HEAD scan: the only two IDs it flagged were fakes — a pattern-shaped string I planted and the example key AWS itself publishes in its documentation. A regex scanner cannot tell a documented example from a live key. The attackers know that too. They do not need precision at 28,000-repository scale; they need recall, and sorting real from fake is a problem they can solve later, with your credentials, at their leisure.\n\nIf you take one action from the GhostAction wave, make it this: run that same `git log -p` scan against your own repositories before someone else's workflow does. If it finds anything, do not delete it and move on. Rotate it, then delete it — in that order, because the scan order in this post is the order the payload uses, and it reads history first.\n\nSources: GitGuardian's GhostAction research as reported by The Hacker News, \"GhostAction Compromises About 1,900 GitHub Accounts, Targets Over 30,000 Repositories\" (October 15, 2026) — campaign figures, payload version history and the context-capture detail are theirs. The repository, planted credentials and all scan results above are mine, generated for this post; every planted credential is a random string that was never a real key.", "url": "https://wpnews.pro/news/ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-all-30", "canonical_source": "https://dev.to/frankchu/ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-recovered-all-30-60o", "published_at": "2026-10-19 23:34:53+00:00", "updated_at": "2026-10-19 23:45:39.617519+00:00", "lang": "en", "topics": ["ai-safety", "developer-tools", "ai-agents"], "entities": ["GhostAction", "GitGuardian", "GitHub", "AWS", "The Hacker News", "GitLab"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-all-30", "markdown": "https://wpnews.pro/news/ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-all-30.md", "text": "https://wpnews.pro/news/ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-all-30.txt", "jsonld": "https://wpnews.pro/news/ghostaction-now-scans-your-git-history-for-secrets-i-deleted-30-keys-and-all-30.jsonld"}}