The file is clean. What does the credential issuer say?
You deleted the secret. Did you revoke its access? GhostAction makes that question urgent: a compromised maintainer account can introduce a workflow that searches old commits as well as current files. A clean working tree cannot tell you whether the credential it finds still works. That decision lives with the service that issued it.
The October 2026 campaign is the starting point, but the useful deliverable is a way to close the incident with evidence. I separate three questions: where secret material remains, whether the issuer still accepts it, and whether the attacker can introduce another workflow. This analysis uses public research and GitHub documentation; no campaign payload was run here. [1][2]
Git history becomes input to the compromised runner
StepSecurity describes a malicious security-audit.yml committed directly under a compromised maintainer identity. Its checkout requests full history. The script then uses git log -p --all to inspect patches. It also attempts to collect configured Actions secret values by inserting names discovered in existing workflows. Names identify what to request; the values are what the attacker wants. [1]
Consider the illustrative history below. Commit B removes the token from the latest file, while commit A still records it. A history-aware search can therefore recover the old text. The attacker's collection is still bounded by fetched refs, matching patterns and the payload's output limits. Do not turn that capability into a claim that every historical secret was successfully extracted.
Illustrative repository history; no real credential
A: config.env contains API_TOKEN=DEMO_NOT_A_REAL_TOKEN
B: config.env no longer contains API_TOKEN
Current file: absent
Earlier commit: present
Issuer status: a separate questionCan a recovered secret still authenticate?
Recoverability and validity are independent properties. An old token can remain visible after revocation without still granting access. A token can also disappear from the repository you control while remaining usable from somebody else's copy. GitHub recommends revoking or rotating exposed credentials first; rewriting history addresses remaining copies, with coordination required for clones, forks and references. [2]
This distinction changes how I read cleanup statistics. A count of repositories containing old secret text measures public residue, not the number of credentials an issuer would still accept. It also changes the acceptance test: replacing a CI variable is not enough unless the previous credential is disabled at its issuer. Record that separately from whether builds work with the replacement.
Old credential accepted?
Yes No
Secret text recoverable Access remains Residual disclosure
Secret text no longer found Access may remain Both checks needed
A repository scan cannot answer the issuer-status column.Which control actually stops the next workflow?
Review requirements help only where they are enforced. GitHub's approval control for workflows from public forks concerns that contribution path; it is not a universal approval gate for a maintainer's direct push. StepSecurity reports an approval gate stopping particular observed runs, but that observation does not establish that the fork setting protects every repository against this campaign. [1][3]
For a protected branch, require pull requests and the relevant code-owner review, then inspect who can bypass the rule. A CODEOWNERS entry for .github/workflows/ supplies ownership; the branch rule makes that review mandatory. Protect CODEOWNERS itself, and examine other branches whose push workflows can receive secrets. Protecting main alone does not describe every executable workflow path. [4][5]
A read-only repository token can accompany secret theft
Reducing GITHUB_TOKEN permissions is useful, but it does not revoke a cloud credential passed separately into a job. The observed workflow could operate with repository contents set to read while collecting other credentials. A permissions review must therefore inventory both the built-in token and each separate secret made available to execution. [1]
My review follows a concrete chain: who may change the workflow, what event starts it, what identity and secrets the job receives, and which destinations it can contact. For a publishing job, the question is whether a workflow writer can turn that job into a credential reader. Restricting repository writes answers only one part of that chain. This is an architectural review question, not a claim that every runner exposed every secret.
Contain access before polishing repository history
Preserve the workflow revision, run identifiers and relevant audit records before cleanup removes context. Stop the malicious execution path and revoke the compromised maintainer credential. Then inventory current job secrets and historical credentials within the exposure scope, assign each to an owner, and establish revocation at the issuing service. Where validity cannot be established, treat it as unresolved rather than declaring the repository clean. [1][2]
A replacement credential must go into a trusted execution path. Otherwise the same compromised workflow can read it on the next run. Historical cleanup comes with its own coordination work, and it cannot recall copies already obtained by an attacker. For keys that can create sessions or other credentials, review that downstream access too; disabling the original secret does not logically prove that no separate access was established.
Ask for a closure record, not a clean screenshot
A remediation record should let another engineer distinguish completed work from assumptions. For each exposed credential, keep its non-secret identifier, owner, issuing system, exposure window, revocation evidence and replacement deployment status. Record how the injection identity was contained and how the workflow path was restricted. The worksheet below is a proposed review artifact, not a transcript of this incident.
The buyer's question becomes precise: can your team show that previously exposed access is no longer accepted and that the replacement cannot leak through the same route? That is the evidence I would ask for in remediation verification. It makes the difference between closing a ticket and closing the access it was meant to remove.
Credential ID / owner / issuer: ____________________
Exposure scope and evidence: _______________________
Old credential disabled at issuer: _________________
Replacement deployed through trusted workflow: _____
Compromised maintainer access contained: ____________
Other credentials or sessions investigated: _________
Remaining copies / uncertainty / responsible owner: _Sources
Need this checked in your own product?
Remediation & fix verificationWant to learn to find vulnerabilities like this yourself?
Secure code review course, one to one