Managed Detection and Response
RecipeLister: A Recipe for Disaster
July 17, 2025 | 5 min read
Thomas Elkins
SOC Security Analyst III

The BlueVoyant SOC consistently monitors and analyzes threats within customers instances 24x7. One threat we have been tracking and observing has been a free-ware software known as RecipeLister. This software claims to provide users with the capabilities of viewing and downloading recipes in order to assist in the journey of staying healthy. While this capability was rather appetizing, we discovered there was more to be unpacked by this software.
What is RecipeLister?
RecipeLister is a free ware software that claims to allow users to leisurely view and download recipes from its database and aid in the good old journey of staying healthy. This software was originally reported by Blumira and a user that goes by Dingus.

The website offers a healthy amount of recipes for viewing pleasure. The 'About' section sums up their supposed service nicely:
“Recipelister helps you discover delicious recipes from around the world. Whether you're looking for a quick dinner idea, planning a special meal, or just curious about new cuisines, we've got you covered.
Our extensive database includes recipes for every occasion, dietary preference, and skill level. Explore, cook, and enjoy!”
We can certainly confirm that they have an extensive library, and it is within this that the threat actor finds value for their purposes.
Unsurprisingly, the threat actor made the software available for only Windows, indicating they may eventually have future versions available for Mac and Linux.

The threat actor also uses malvertising and SEO poisoning, ensuring they are the top result, which was also reported by Blumira.
Unpacking RecipeLister
The ‘recipelister’ program is packed using Nullsoft Scriptable Install System (NSIS), which enables the software author to customize the installation process through an NSIS script.

We also observed that the program was signed using a digital certificate under the company name ‘Global Tech Allies Ltd.’ A search on VirusTotal revealed another software named ‘Lookupkitchen.com’, which was first submitted in April. This suggests that the threat actor may have started their campaign around that time.
Upon analyzing the initial contents, we found that the ‘$Plugins’ directory includes the standard NSIS binaries, along with an intriguing 7z file named ‘app-64.7z’.

After expanding the contents within app-64.7z, we were immediately drawn to a text file containing the string ‘Electron’. That made us immediately aware, we were dealing with some ‘Electron’ App. Electron is an application built using NodeJS which is designed to load and execute JavaScript files. Developers will include a main script along with modules that are used at run time. These files are located within the resources folder named ‘asar.app’. The ‘asar.app’ can be extracted using the npx application ‘asar’, supplying the following commands:
‘npx asar extract <name of .app> <name of output folder>’
Contained within this extracted folder were the JS files run by the Electron application, in this case named ‘Recipe Finder – Recipe Lister.exe’. The main file of interest was ‘main.js’.
Main.js
Upon initial inspection of the ‘main.js’ file, we were greeted immediately with an interesting line of commented code:
“// MinimalDecodeStago.js”.
Following that line of commented code, we observed interesting variables being set:
‘const crypto = require("crypto");
const zlib = require('zlib');
const INVISIBLE_ONE = '\u200b';
const INVISIBLE_ZERO = '\u200c';
const KEY = Buffer.from("6829085424920489caslxk1230120412");’

The values '\u200b' and '\u200c' are commonly used by steganographic tools in order to hide binary code in images and files. The value '\u200b' is equal to 1 while '\u200c' is equal to 0.
Further analysis of the main.js showed that the purpose of the script was to read in recipe cards from the URL ‘hxxps://recipelister[.]com/api/themealdb/random?number=’ where number is randomly generated using the built in function ‘rand’. When we viewed one of the recipe cards stored at the URL ‘hxxps://recipelister[.]com/api/themealdb/random?number=20’, we immediately saw that the recipe card was interlaced with the values '\u200b' and '\u200c'.

Main.Js contained a function named ‘cleanJson’, which is responsible for parsing the JSON values and pulling out the strings within the key-value ‘meal.idMeal’. After extracting the strings, the function then searches for the values '\u200b' and '\u200c' and stores the results into arrays. After finding all the values, the function then joins the arrays together, generating one long string. The string is then pushed into a new function, ‘decodePayload’.

The function ‘decodePayload’ is responsible for converting the values '\u200b' and '\u200c' and turning them into their binary values. The function then splits the binary values into groups of 8 which are then converted to character values and stored in the variable ‘b64Chars’. After all the binary code has been converted to their respective character values, they are then joined back into a giant string saved under the variable name, ‘b64StrEncrypted’ and pushed into another function, ‘decryptString’.

As the function name suggests, it is responsible for decrypting the ‘b64StrEncrypted’ string using AES GCM. The function takes in two arguments, being ‘b64StrEncrypted’ and ‘key’, which was declared at the beginning of the script. This function attempts to convert the data stored in ‘b64StrEncrypted’ and convert it from Base64, saving the result into ‘Buffer’. The function then reads the first 12 bytes from the converted data and saves it as the nonce. The variable ‘ciphertext’ contains the decoded data starting from offset 12 and ends 16 bytes before the end. The authentication tag is the final 16 bytes. The data is then pushed into the AES-GCM decryption function. Interestingly, the function contains a ‘catch’, indicating that it expects the function to potentially fail.

If the AES decryption is successful, the output is passed through a Gunzip decompression function and then converted to UTF-8 encoding contained within function ‘decodePayload’. The resulting data is stored in a variable called decodedData and executed using the line const ‘{ exec } = require('child_process')’. This code leverages Node.js’s child process module to run the contents.
If the AES Decryption fails, the script loops back to the beginning and attempts to read in a new recipe card from the URL ‘hxxps://recipelister[.]com/api/themealdb/random?number=’, continuing the same process as described above.
While reviewing the contents hosted at ‘hxxps://recipelister[.]com/api/themealdb/random?number=’, we observed that multiple recipes were available. Furthermore, each time the page was refreshed, a new recipe appeared, even when the same number parameter was used. We concluded that this behavior was due to the ‘random?’ value in the URL being mapped to the PHP file ‘randomselection.php’, which likely serves a random recipe each time it is accessed.

Based on these findings, we believe this functionality operates similarly to a sleep function. It helps ensure that the program’s execution doesn’t immediately draw attention, allowing it to run silently in the background without the user’s knowledge.
Conclusion
As of this writing, we have not yet determined the final payloads. However, what we can confirm is that the purpose of this software is to stealthily execute code while masquerading as a benign digital meal database.
Related Reading
Supply Chain Defense
Third-Party Breaches: Why You Should be Prioritizing Supply Chain Cyber Risk Today
Managed Detection and Response
Enhancing the Skills and Threat Detections of In-House SOCs and Security Teams