Malicious shell script found on `git.riot-os.org`

Hi all,

while reviewing the files of our old Gitea instance to investigate the outage of our CI system https://ci.riot-os.org between October 1 and October 2, 2026, we discovered that a malicious shell script has been interleaved with the router log entries of the RIOT-OS/RIOT and murdock/RIOT repositories on https://git.riot-os.org. I’d like to share what we know so far, since users of https://git.riot-os.org may have been effected.

What happened

After an update of the Docker package on our community server on October 1, 2026, at 13:05 CET, and the resulting Docker service restart, https://git.riot-os.org (a Gitea docker container) stopped working properly: Pushing commits to the repository murdock/RIOT still worked. However, cloning these commits from the CI workers then failed with the following error resulting the CI tests not even to start:

fatal: early EOF
fatal: fetch-pack: invalid index-pack output

We use https://git.riot-os.org to host Git mirror of our main repository on GitHub (https://github.com/RIOT/RIOT-OS) and use the repository murdock/RIOT to distribute the RIOT code between our CI workers for https://ci.riot-os.org.

After 1,5 days of testing and debugging, we suspected that something broke in the data directory during the restart of the Gitea container. As a result, I backed up the files for later analysis and set-up a new Forgejo container (Forgejo is an updated fork of Gitea) to benefit from the newest version, with a new data directory. In the process I rotated secrets, such as OAuth Client secrets and server SSH keys.

Later, on the evening of October 2 and after everything was up and running again, I started analysing the old Gitea files. I noticed a suspicious git config file git/.gitconfig which was created right when the Docker restart happened. That config defined multiple upload hooks uploadpack.packObjectsHook calling an equally suspicious script (which was created at the same time) gitea/home/.pwn. I asked GLM-5.3 to analyse this scripts and here is what we know resulting from that: Someone managed to inject that script into the log stream, so that it appears between legitimate log lines such as

#router: slow      GET /RIOT-OS/RIOT/compare/2025.10...2021.04-RC2?... @ repo/compare.go:634(repo.CompareDiff)

This resulted in the log to be dumped into file system of the container. The injected script (repeated many times throughout the log file and the .pwn script itself) does the following:

  1. Changes into /var/tmp, /tmp, /dev/shm, or / (first one that succeeds),
  2. Defines a _get() helper that tries wget, busybox wget, curl, python3, and python in turn,
  3. Sends a beacon to http://[C2 Server IP]:8081/b-52735001,
  4. Downloads a binary (.k1e, served as bins/1e) from one of three C2 servers, chmod 755s it, and runs it detached via nohup under the process name app-gitea (i.e., masquerading as a legitimate Gitea process),
  5. Downloads and executes a second-stage script (.bi, served as /i) with the primary C2 URL as argument.

We confirmed that only the docker container was compromised, and, when it was rebuild using docker-compose, only after someone tried to fetch something from the effected Git repositories.

What this means for you

  • If you only browsed the RIOT repositories on git.riot-os.org or the Gitea web interface: you are not affected. The script was never served through the web UI.
  • If you downloaded, processed, or mirrored the RIOT-OS/RIOT repository from our git.riot-os.org instance between October 1 and October 2: please check if the commit hashes are the same as in our main GitHub Repository GitHub - RIOT-OS/RIOT: RIOT - The friendly OS for IoT · GitHub.
  • If you operate a Gitea/Forgejo instance yourself: treat this as a heads-up. Check your logs for the indicators below and make sure your internal API (/api/internal/) is not reachable from untrusted networks and that INTERNAL_TOKEN is properly protected.
  • The hosts firewall prevented the script to open any malicious ports to the outside world, so at no point were malicious services provided by git.riot-os.org.

Indicators of compromise (IoCs)

  • Files named .k1e or .bi in /var/tmp, /tmp, /dev/shm, or /
  • A running process named app-gitea that is not your actual Gitea binary
  • Outbound connections to external IPs you do not recognize
  • POST /api/internal/manager/add-logger entries in your Gitea logs from unexpected source IPs

What we did to prevent such an incident in the future

  • We changed to a newer version of Forgejo (an updated fork of Gitea) and in the process created a completely new data directory.
  • We rotated all secrets, including SSH server keys for git.riot-os.org (if you clone/fetch from git.riot-os.org you will notice).
  • We restricted user access to the new Forgejo instance (please ask Mikolai, Elena, or me if you need an account).
  • We restricted access to /api/internal from external IPs.
  • We blocked the C2 IPs in our firewall.
  • We restricted access to git.riot-os.org based on GeoIP.
  • We will follow-up in this thread if there are investigation updates.

If you have any further questions, please let me know, but please note that this is not really my main area of expertise.

Cheers, Martine


Declaration of AI tools

In accordance with the RIOT AI policy, I hereby declare that parts of this report were prepared with the assistance of AI tools:

  • Tool(s) used: Z.ai GLM-5.3 Flash (via You.com), conversational AI assistant
  • Scope of use: Initial analysis of the captured log file (identification of the injected shell dropper, extraction of IoCs such as C2 addresses and dropped file names), drafting of this incident report, and the formulation of the AI declaration itself
  • Generated: 2026-10-06
  • Human review: All technical findings (injection mechanism hypothesis, impact assessment, recommended mitigations) were reviewed, verified against the original data, and edited by myself before publication. The assessment of the injection vector is explicitly marked as unconfirmed and remains subject to the ongoing investigation.
5 Likes

My reading is that the log file just showed the evidence, but the RCE was a bug in Gitea: https://www.cve.org/CVERecord?id=CVE-2026-60004 (that one talks about diffpatch instead of compare but the rest sounds very similar).

1 Like