Executive Summary
- Censys uncovered a potentially new C2 server called the “SCOUT PROJECT,” the source code of which can be found here.
- By analyzing files left open to the public, we found that a potential threat actor is using several newly reported CVEs as an attack vector: CVE-2025-30208 (ViteJS), CVE-2025-3248 (Langflow AI), CVE-2025-29927 (NextJS)
Identifying a novel C2
Censys has recently been closely monitoring HTTP-based open directories that exhibit suspicious behaviors, such as high ephemerality — where servers appear and disappear within short timeframes — and the presence of suspicious files that may contain malicious code. Our internal system automatically identifies files likely to contain malicious content, creates a copy, and analyzes them using multiple classification engines.
In a recent case, our monitoring flagged a single host containing the source code for a command-and-control (C2) server, and a backdoor build system; a set of tools that (to our knowledge) has not been publicly documented before. We found no references to it in VirusTotal or ReversingLabs, but based on screenshots included within the program’s documentation directory, we can confirm that the malware has existed since at least May 7, 2024.

The malware was discovered within a ZIP archive named Release_final.zip on a Linode host in Japan. Although the code and documentation are written in Vietnamese, the archive contains no clear attribution beyond a startup banner displayed by the client, reading “SCOUT PROJECT,” and references to “Scout malware.” While a Google search for “Scout malware” returns some results, none of the matches reviewed correspond to this specific codebase.
This toolkit consists of four primary components: the C2 server, the C2 admin client, the dropper builder, and the payload. The builder creates a malicious executable disguised as a Microsoft Word document. When executed, the dropper places two files into C:Program DataVault: steam2.exe and tier0_s.dll (VirusTotal link).
In this case, the actor generated a file called test1.exe using their IP address as the C2 server on port TCP/8080 and placed the output into their public HTML directory.

Agent <-> C2 Communication
Once the agent is running, it sleeps for a configurable number of seconds before connecting to the designated C2 server. It then sends an HTTP POST request to /admin/edit/upload_image.aspx to retrieve new tasks and upload any task responses.
Each POST request begins with a fake PNG file header. If the server does not detect this expected header, the request is immediately discarded.

The framing format of the data found after the fake PNG header is as follows:
| Field | Size |
|---|---|
| Payload size | 4 bytes |
| Encryption key | 16 bytes |
| Body | Remaining bytes |
The body will be decrypted once the frame has been read and decrypted using the client-defined encryption key with ARC4. The contents are then treated as a command that is in the following format:
| Field | Offset | Size | Type |
| command | 0–3 | 4 bytes | ASCII command |
| agent_id | 4–7 | 4 bytes | an unsigned 32-bit little-endian integer representing the ID of the remote client. |
The agent’s initial message to the C2 server is a CMD_INFO packet, used to register with the server. This packet contains two fields: sleepTime, which specifies the number of seconds the agent waits between check-ins, and computerInfo, a string combining the username and hostname. The server generates a CRC32 checksum of the computerInfo to produce a unique agent ID, which it uses to index the list of registered agents.
In response, the C2 server sends its own CMD_INFO packet, followed by the 4-byte agent ID. This response is encrypted using the client-generated RC4 key and wrapped inside a fake PNG header. Once registration is complete, the server can assign new tasks to the connected agent.
The following is an overview of the encoded tasks that the agent can retrieve:
| Command | Arguments | Purpose |
| NONE |
|
Tells the agent to do nothing (idle). |
| TIME |
|
Instruct agent to update its sleep interval. |
| CMD |
|
Instruct agent to run a system command |
| DOWN |
|
Instruct agent to download a file from a URL and save it locally. |
| UPLO |
|
Instruct agent to upload a specific file back to the C2 server. |
| 4444 |
|
Instruct agent to initiate a TCP reverse shell connection to a remote host. |
| INFO |
|
Sent during agent registration to confirm agent ID assignment. |
| HI!! |
|
Request the agent to re-register |
Tasks are issued through the /client_api HTTP endpoint, using POST requests. Unlike agent communications, client requests are simple JSON structures that allow administrators to retrieve agent information and assign tasks. Each client request must include a token value in the JSON body, which serves as a basic password. The token is specified when the server is started via the command line.
The following table contains all of the known commands the C2 administrator can issue to the C2 server.
Files uploaded from agents to the C2 server can be retrieved by sending a GET request to the /file_storage/ HTTP endpoint, using a single query parameter, token, whose value must match the password specified when the server was started.
Next, we attempted to determine if this C2 server can be found on any other server on the internet. To do this, we determined that the route for the client API would be a good target given that if we did not have the correct authentication token, the server would respond with a very unique JSON blob:

If we scanned for this endpoint, we would only need to set the appropriate Content-Type header and look for a JSON-formatted response containing the string “Wrong token” along with a 400 status code.
Additionally, we know that the server is based on the Python Flask framework, which means its HTTP responses will include a Server header containing the string “Werkzeug”. Since this C2 server does not define a route for /, we could identify potential hosts by querying for servers that both respond with a 404 status code and have “Werkzeug” in their headers. The following search query was used:
This query returned just over 100,000 hosts. We then scanned these hosts using httpx with the following command:
$ cat input.hosts | httpx -bp -mc 400 -path /client_api -x POST -H “Content-Type: text/plain” -ms “must be application/json”
At the time of the scan, we found no hosts that matched the specific response patterns associated with this server. However we will continue to monitor for new deployments going forward.
We have made the source code of this server publicly available in our GitHub repository.
Recon and Exploitation
By reviewing many of the artifacts left over in the exposed directory, we discovered that this actor was scanning for multiple known and recent vulnerabilities:
A custom Nuclei template for finding vulnerable instances of ViteJS affected by CVE-2025-30208, which allows for reading arbitrary files from the system. A service that has over 17,000 instances listening online.

We also observed this actor scanning for CVE-2025-3248, a critical vulnerability in Langflow AI that can lead to remote code execution. Their logs indicated successful identification of just under 100 vulnerable targets. However, at the time of analysis, there were over 1,000 Langflow AI instances accessible on the internet.

While seemingly unsuccessful, the actor had developed a customized Nuclei template for CVE-2025-29927, a vulnerability in Next.js that can potentially allow complete authentication bypasses under specific conditions.

The individual appears to have successfully exfiltrated data from a Chinese NFT application using the tool git-dumper. They also attempted various directory traversal attacks against high-profile sites, including asus.com, nasa.gov, and continental.com. Whether those attacks were successful or not is outside the scope of our research.

