Author: Joker&Thinking
Edited by: KrsMt.
In early July 2025, the SlowMist security team received a request for help from a victim user, asking for assistance in analyzing the cause of the theft of his crypto assets. The investigation found that the incident originated from the user's use of an open source project zldp2002/solana-pumpfun-bot hosted on GitHub, which triggered a covert theft of coins. For details, see GitHub's popular Solana tool has hidden coin theft traps.
Recently, another user used a similar open source project, audiofilter/pumpfun-pumpswap-sniper-copy-trading-bot, which resulted in the theft of encrypted assets, and contacted the SlowMist security team. In response, the team further analyzed the attack method.
We first used static analysis to find traps set by attackers. After analysis, we found that the suspicious code was located in the /src/common/config.rs configuration file, mainly in the create_coingecko_proxy() method:
As can be seen from the code, the create_coingecko_proxy() method first calls import_wallet(), which further calls import_env_var() to obtain the private key.
In the import_env_var() method, it is mainly used to obtain the environment variable configuration information in the .env file.
During the call, if the environment variable exists, it will return directly; if it does not exist, it will enter the Err(e) branch and print the error message. Since there is a loop {} with no exit condition, resources will continue to be consumed.
Sensitive information like PRIVATE_KEY (private key) is also stored in .env file.
Back to the import_wallet() method, when import_env_var() is called to obtain the PRIVATE_KEY (private key), the malicious code will determine the length of the private key:
The malicious code then uses Arc to encapsulate the private key information to support multi-threaded sharing.
Back to the create_coingecko_proxy() method, after successfully obtaining the private key information, the malicious code then decodes the malicious URL address.
The method first gets the encoded HELIUS_PROXY (attacker server address) hardcoded constant.
The malicious code then decodes HELIUS_PROXY (the attacker's server address) using bs58, converts the decoded result into a byte array, and further converts the byte array into a UTF-8 string using from_utf8().
By writing a script, the real address of HELIUS_PROXY after decoding can be restored as follows:
After successfully decoding the URL (http://103.35.189.28:5000/api/wallets), the malicious code first creates an HTTP client and converts the obtained private key information payer into a Base58 string using to_base58_string().
Subsequently, the malicious code constructs a JSON request body and encapsulates the converted private key information in it. By constructing a POST request, the private key and other data are sent to the server pointed to by the above URL, while ignoring the response result.
Regardless of the result returned by the server, the malicious code will continue to run to avoid user awareness.
In addition, the create_coingecko_proxy() method also contains normal functions such as obtaining prices to cover up its malicious behavior; the method name itself is also disguised and confusing.
Through analysis, we can know that the create_coingecko_proxy() method is called when the application starts, specifically in the configuration file initialization phase of the main() method in main.rs.
In the new() method of the configuration file src/common/config.rs, the malicious code first loads the .env file and then calls the create_coingecko_proxy() method.
According to analysis, the server's IP address is located in the United States.
(https://www.virustotal.com/gui/ip-address/103.35.189.28)
It is observed that the project was updated recently (July 17, 2025) on GitHub, and the main changes are concentrated in the configuration file config.rs in the src directory.
In the src/common/config.rs file, you can see that the original address encoding of HELIUS_PROXY (attacker server address) has been replaced with the new encoding.
After using the script to decode the original address encoding, the original server address can be obtained.
In order to more intuitively observe the theft process of malicious code, we used a dynamic analysis method and wrote a Python script to generate Solana public and private key pairs for testing.
At the same time, we built an HTTP server on the server that can receive POST requests.
Write a Python script to generate the code corresponding to the test server, and replace it with the malicious server address code set by the original attacker, that is, HELIUS_PROXY (attacker server address).
Then, replace the PRIVATE_KEY in the .env file with the test private key you just generated.
Next, launch the malicious code and observe the response of the server-side interface.
We can see that the test server successfully received the JSON data sent by the malicious project, which contained the PRIVATE_KEY information.
IPs:
103.35.189.28
Domains:
storebackend-qpq3.onrender.com
SHA256:
Malicious warehouse:
Similar implementation methods:
In the attack method shared this time, the attacker disguised himself as a legitimate open source project to trick users into downloading and executing the malicious code. The project reads sensitive information from the .env file locally and transmits the stolen private key to a server controlled by the attacker. This type of attack is usually combined with social engineering techniques, and users may fall into the trap if they are not careful.
We recommend that developers and users be highly vigilant about GitHub projects from unknown sources, especially when it comes to wallet or private key operations. If you really need to run or debug, it is recommended to do so in an independent environment without sensitive data to avoid executing malicious programs and commands from unknown sources.