|
Recently, a recruiter from Cryptic Heaven contacted me on LinkedIn with an offer to work together. The company supposedly develops a financial system for users of cryptocurrency credit cards. The offer looked quite ordinary: they liked my experience and wanted to discuss possible cooperation. I replied that I was interested in learning more about the project, the position, and the working conditions. In response, I received the following message:
That is, I was being asked to download the documents, look through the project, and fill in the contract. The link led to a ZIP archive, And the trap does not require launching some suspicious Let me explain how it works. What was inside the archiveThe archive contained The README said that the documents were split across three branches:
The suggestion was to first read the job description, then study the agreement, and after that look at the code. At first glance, everything seemed quite logical. A developer had been sent a repository where they could look at the project and its documentation. The agreement itself, though, turned out to be a template with blank fields. It did not specify the legal entity, the amount of pay, the jurisdiction, or many other terms. The Smart Contract Developer job description also had many blank fields. But there was something more interesting. The ZIP contained a Usually, a developer gets a link to GitHub or GitLab and runs And this turned out to be crucial. A little about how Git worksMost developers think of Git as a tool for storing the history of changes and creating branches and commits. But Git has mechanisms that allow it to run external programs. The first mechanism is Git Hooks. These are scripts that Git calls in response to certain events. For example, before a commit, after switching branches, or before sending changes to a server. The second mechanism is Git Filters. They allow the contents of files to be transformed when data is moved between the working directory and Git’s internal storage. Both mechanisms are entirely legitimate. They are used to automate development, format files, and perform various checks. The problem arises when an attacker preconfigures them in a repository you are about to open on your computer. The first part of the attack – redirecting the location of Git HooksI looked into The following setting was there:
By default, Git looks for hooks in the But the In this case, the hooks were moved to:
Why put them there? Because most developers will not dig into the contents of There was a Its contents:
Just one command. The That is, when running the command:
Git will first switch branches, and then run this script. Why did the malicious actor need The second part – Git FiltersThe following setting was found in the same
This defines a custom filter named The Usually, this mechanism is used, for example, to normalize file contents before saving. But Git still needs to know which files to apply this filter to. For this, The archive I received contained:
With the following contents:
The asterisk means that the filter is assigned to all matching files. So, during certain operations, Git will run And here an interesting detail appears. The Thus, an entirely ordinary I separately checked this in a safe test repository, replacing the filter with a harmless script that only records the fact of its invocation in a log. As a result, Now it is clear why the attacker put an instruction in the README to switch between branches. Part Three – The Malicious Script ItselfAll that remained was to look at the contents of The file is a shell script that, at first glance, looks a little more complicated than one might expect. At the beginning, two service files are defined:
The first file records the time of the last call to the filter. The second is used as a lock. The thing is, Git can call the If malicious code were downloaded and launched immediately on every call, we would end up with many parallel launches. The script authors solved this problem. Each time the filter is called, the timestamp is updated. A background process checks how much time has passed since the last call. Until two seconds have passed, it keeps waiting.
This is a kind of debounce: wait until the series of calls to the filter is over, and only then perform the main action. To prevent several watchers from being launched at the same time, a lock directory is created using After the wait, the most interesting part runs:
This is a shortened version of the actual code from the archive. I replaced the download address with a placeholder. The meaning is simple. The script tries to determine the operating system, download additional code from a remote server, and execute it immediately. For Linux and macOS, it is set up to run through Interesting, the attacker uses the The remote server in the archive was located on the It is impossible to determine what exactly the downloaded script does from the ZIP contents alone. It could be a loader for the next stage of the attack, data theft, or some other malicious action. But the very fact that remote code is secretly downloaded and executed already says enough. And everything runs in the background, while standard output and errors are redirected to That means the user may not notice anything at all. Why the filter does not break GitAt the end of
This is also an important detail. Git expects the But the attacker does not need to transform anything. So the script simply returns the data it received unchanged. To Git, this filter looks like it is working: the data came in, was processed, and came back. At the same time, a background process was started that is supposed to download and execute remote code. This means the malicious operation itself does not require any noticeable changes to the project’s files. The most interesting part – how the attack can work without user involvementLet’s imagine an ordinary scenario. You download a ZIP, unpack it, and see If you simply open the folder in Windows File Explorer, Git does not start automatically. Simply unpacking the archive also does not trigger Git Hooks or Git Filters. But the interesting scenarios begin after that. The first option – VS Code. Suppose your Markdown files are associated with Visual Studio Code. You double-click README to read the instructions. VS Code can automatically detect Git repositories. If repository detection for open files is enabled, it can find After detecting the repository, the Git extension may run If the repository is trusted and Git really performs this check, an opportunity appears to run the malicious filter. This gives us the following chain:
An important caveat: simply opening the README in VS Code does not guarantee that the attack will run. This depends on the editor settings, trust in the workspace, automatic repository detection, and the specific Git operations. But this scenario is quite realistic. Second option – terminal. Many developers use a Git-aware command-line prompt. For example, after changing to a directory, the terminal shows:
To display the branch name, some terminal themes use By themselves, they should not run the But other configurations additionally check the state of the working directory through And in this case, a simple move into a directory:
may indirectly lead to a malicious script being executed. Not because the The third option – following the instructions in the README. This is the most obvious scenario. The user reads that the documents are located on different branches and runs:
As a result, Git may call the filter while processing files, and after switching branches it will additionally run That, in turn, will run So the archive’s authors provided several ways for the trap to trigger. How does all this work on Windows if the script is written for Bash?At first glance, it may seem that Windows is protected against this kind of attack, since
But there is a nuance. Git for Windows comes with a Unix-like environment and includes That is why Git can run shell scripts even when the user is working in PowerShell or CMD. You do not need to open Git Bash yourself. If Git calls a script with the corresponding interpreter, it can run through the shell supplied with Git. And the script itself already has a separate option for Windows – downloading the contents through So the attack was designed from the start to target more than just Linux. Why did they send a ZIP instead of a link to GitHub?In my view, this is one of the main features of the attack. When we run an ordinary But the remote repository’s local Local Git Hooks are not transferred by an ordinary clone as ready-to-run hooks either. Here, the attacker sent a ZIP that already contained a fully prepared It contained:
After unpacking it, the user got a ready-to-use local Git repository with all the malicious settings. And Git could start using them at the first suitable opportunity. That is, the ZIP here is needed not simply for the convenience of transferring documents. It lets the sender pass along exactly the local Git configuration required for the trap to work. What it comes down toThe result is a rather interesting attack scheme. The attacker does not ask you to run some unknown EXE file. Does not suggest disabling antivirus. Does not ask you to install an unknown package. Instead, they send an ordinary-looking project that uses standard Git mechanisms. A file filter is configured in one place. The path to hooks is changed in another. A shell script is stored in a third. The README tells you to switch between branches. Each element on its own can look relatively harmless. But together, they form a chain for hidden code execution. And what is especially unpleasant is that the launch can happen as a result of actions that a developer does not perceive at all as running someone else’s program. So I would formulate several rules for working with unfamiliar projects.
I want to emphasize separately that the presence of a downloader does not prove that the computer was successfully infected. To establish that, it is necessary to determine whether the filter actually ran and what code was received from the remote server. But there is practically no doubt about the purpose of the setup we found: it is intended to secretly launch remote code on a developer’s computer. I liked the technical side of this attack. Not because it does anything fundamentally new, but because of how familiar tools were used here. We are used to thinking that And this, perhaps, is the main takeaway from the whole story. submitted by /u/ievkz |
Source: Reddit r/OSINT · 2026-11-14