☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
Erlang logo [ WEBSITE ] [ VENDOR STATS ]
SOON 🐛 CWE-23
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2026-47078

CVE-2026-47078 — Relative path traversal in zip:unzip/zip:extract via check_dir_level depth-counter bypass
📅 PUBLISHED: 2026-07-27 00:00 UTC 🔄 UPDATED: 2026-09-23 20:42 UTC
[ OFFICIAL PATCH DEPLOYED ↓ ] FIX: CONFIRMED — 3+ independent sources confirm fix ⏳ CVSS score pending NVD analysis
[ DEFENSE PATCH ↓ ]
💣 PoC: Public
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 0.15%
👁️
0.15% probability
3.7× above the median CVE
Tier: ELEVATED
30-day exploitation window · FIRST.org · updated daily
🥷 MITRE: T1190
👁️
MITRE ATT&CK Tactic - Describes the strategy hackers use to execute this attack.
Country: Sweden License: Open Source
Patch available — upgrade to latest release
CVSS SEVERITY SCALE
9.0–10.0 CRITICAL
7.0–8.9 HIGH
4.0–6.9 MEDIUM
0.1–3.9 LOW
0.0 NONE
SOON
PENDING NVD
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2026-47078 is a relative path traversal vulnerability in the Erlang/OTP standard library's zip module (lib/stdlib/src/zip.erl), specifically within the zip:unzip/1,2 and zip:extract/1,2 functions. The flaw exists in the zip:check_dir_level/2 validation logic, which uses an integer depth counter that can be manipulated to bypass path traversal checks entirely, allowing a crafted ZIP archive to write files outside the intended extraction directory. Any application using the Erlang OTP stdlib zip module to extract untrusted archives — including HTTP file upload handlers, firmware update mechanisms, package managers, or archive-processing microservices — is susceptible. Successful exploitation results in arbitrary file write on the host filesystem, which can escalate to remote code execution depending on where the overwritten file is placed (e.g., ~/.ssh/authorized_keys, web root scripts, cron jobs, or application config files). Patches are available for OTP 27.3.4.15, 28.5.0.4, and 29.0.4, but the fix is only claimed by a single source and is not yet independently verified.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Technical Analysis

Vulnerability Mechanism

The vulnerable code is located in lib/stdlib/src/zip.erl, specifically in the validation routine zip:check_dir_level/2. The core flaw is a logic error in how directory depth is tracked during ZIP entry path validation.

The validation function maintains a running integer counter that operates as follows:

  • A normal path component (e.g., docs/, images/) increments the counter.
  • A .. component decrements the counter.
  • The check passes only when the final counter value (after the entire path has been processed) is greater than or equal to zero.

The vulnerability becomes exploitable because the counter is only checked at the end of the path string, never during intermediate processing. Consider the crafted path:

../x/y

Step-by-step counter evolution:

Path Component Counter Before Operation Counter After
.. 0 decrement -1
x -1 increment 0
y 0 increment 1

The final counter value is 1 (positive), so validation passes. However, when the path is subsequently joined with the current working directory via the add_cwd function, the path resolves exactly as written: it first traverses up one directory level and then descends into x/y. The zap extractor believes it is writing inside the extraction directory (because the counter recovered to a non-negative value), but the actual filesystem write occurs one directory level above the extraction root.

Why The Check Fails

The fundamental design flaw is that zip:check_dir_level/2 treats the path as a sequence of balanced operations rather than a hierarchical file-system traversal. A path like a/../../../../b or ../x/../../y can produce intermediate negative values that later return to zero or positive, masking the traversal attempt.

More formally, the check validates:

final_depth >= 0

but should validate:

depth_at_every_step >= 0  (for all intermediate depth values)

This is a classic "check at the end only" bug — the same class of vulnerability that has affected tar extraction in multiple languages (e.g., CVE-2004-1536 for tar, various extract_archive implementations in Python and PHP).

Attack Surface

The attack surface includes any Erlang application that:

  1. Accepts ZIP archive uploads (file-sharing services, document management systems)
  2. Processes email attachments through Erlang mail servers
  3. Handles firmware or package updates delivered as ZIP files
  4. Uses zip:unzip/2 or zip:extract/2 on web-served directories
  5. Uses RabbitMQ (Erlang-based) plugin ecosystem where ZIP-based plugin installation occurs

The vulnerability is locally triggerable (requires the ability to supply a crafted archive to the vulnerable function), but because Erlang services frequently expose ZIP extraction through HTTP REST APIs, network-triggered exploitation is often possible.


Exploitation Scenarios

Scenario 1: Web-Based Arbitrary File Write via ZIP Upload

Prerequisites: Target runs an Erlang web service that accepts ZIP file uploads and calls zip:extract/2 to unzip them into a directory, e.g., uploads/.

  1. Reconnaissance: The attacker identifies a target Erlang/OTP application (checking for Server: Erlang/OTP HTTP headers, epmd port 4369, or RabbitMQ management UI). The attacker confirms the OTP version via erlang:system_info(otp_release) exposed through any debug endpoint, or by fingerprinting the application response behavior.

  2. Weaponization: The attacker crafts a malicious ZIP archive using Python's zipfile module or a tool like zip. The archive contains a single entry with the path:

    ../webroot/shell.php
    

    The ZIP central directory contains a filename of ../webroot/shell.php (or, for byte-level precision, the path components are .., webroot, shell.php). Note: some ZIP writers normalize paths before embedding; the attacker must write the raw path directly into the ZIP headers to preserve the ...

    The attacker verifies the ZIP is structurally valid but does not use ZIP file utilities that would normalize the path. A hex editor can be used to confirm ../webroot/shell.php appears in both the local file header and central directory entry.

  3. Payload Delivery: The attacker POSTs the malicious ZIP to the target's file upload endpoint:

    POST /api/upload HTTP/1.1
    Host: target.example.com
    Content-Type: multipart/form-data
    
    --boundary
    Content-Disposition: form-data; name="file"; filename="document.zip"
    Content-Type: application/zip
    
    [binary ZIP payload]
    

    The server receives the file, validates content type (which passes for a readable ZIP), and invokes zip:extract(ZipPath, [{cwd, BaseDir}]).

  4. Execution: The zip module parses the entry path ../webroot/shell.php, check_dir_level computes final depth = 1 (passes validation), and the file is written to BaseDir/../webroot/shell.php — i.e., directly into the web root that serves PHP scripts.

  5. Post-Exploitation Impact: The attacker sends an HTTP request to https://target.example.com/shell.php with the webshell payload, obtaining remote code execution on the server with the privileges of the Erlang application (which is often a dedicated Unix user but may have access to databases, message queues, or a broader trust domain).

Scenario 2: SSH Key Injection via Timed-Use Extraction

Prerequisites: A scheduled Erlang job extracts a ZIP archive from an internal source (e.g., a data pipeline) into a staging directory.

  1. The attacker compromises a low-privilege account or MITM the ZIP download channel (e.g., via DNS spoofing of the internal server).

  2. The attacker crafts a ZIP with multiple entries, including:

    ../.ssh/authorized_keys
    
  3. The ZIP is extracted by zip:extract/2 to the staging dir. check_dir_level validates: .. (counter = -1), .ssh (counter = 0), authorized_keys (counter = 1) — final = 1 → PASS.

  4. The file is written to StagingDir/../.ssh/authorized_keys, appending the attacker's public key to the Erlang service account's authorized keys.

  5. The attacker SSHs into the target as the service account, gaining an interactive shell.

Scenario 3: Configuration File Overwrite Leading to RCE

  1. Attacker uploads a malicious ZIP to an Erlang-based FTP-to-HTTP gateway that extracts archives into user-accessible directories.
  2. The ZIP contains ../etc/nginx/conf.d/malicious.conf.
  3. After extraction, the attacker triggers an nginx reload (via a separate vulnerability or legitimate admin action), loading the new config that proxies attacker-controlled endpoints.
  4. The attacker uses this to pivot internally.

Impact Assessment

Business Impact

  • Confidentiality: Direct write of files to arbitrary filesystem locations d can enable the attacker to read or modify sensitive files if the service account has read permissions on them. If the attacker is able to overwrite source code or config, they can leak secrets.
  • Integrity: Arbitrary file write allows overwriting application binaries, scripts, configuration files, and package caches. The integrity of the entire host can be compromised.
  • Availability: Overwriting critical system files (e.g., /etc/passwd, shared libraries) can cause denial of service. Untrusted ZIP extraction can also create symlink tricks combined with this traversal to delete or corrupt data.
  • Privilege Escalation: If the extraction directory is owned by root (e.g., the Erlang service runs as root — common in Docker setups), the attacker can write /root/.ssh/authorized_keys or /etc/cron.d/ files, achieving full root compromise.

Affected Systems

  • All Erlang/OTP installations from OTP 27.1 through 27.3.4.14, OTP 28.4.x through 28.5.0.3, and OTP 29.0.x through 29.0.3.
  • Every application calling zip:unzip/2 or zip:extract/2 without sandboxing is impacted.
  • Commercial products embedding Erlang: RabbitMQ (uses zip for plugin install), CouchDB (attachments), ejabberd (XMPP file transfer), WhatsApp servers (Erlang backend), and numerous FinTech platforms.

CVSS Rationale

Official CVSS is N/A (no score submitted by CNA). Using engineering judgment with the EPSS score of 0.00152 (4.8% percentile — moderate probability of exploitation), this vulnerability is likely CVSS 7.5–8.8 (High) given network-triggerable attack vector, arbitrary file write, and low complexity, but official scoring is absent.

Blast Radius

  • Single Host: File write outside extraction dir leads to local RCE.
  • Cloud Environment: If the Erlang app runs in a pod with a service account mounted via a volume, writing to that volume can compromise other pods sharing the volume.
  • CICD Pipeline: If a CI runner uses Erlang to extract artifacts, an attacker could inject binaries into the artifact cache, poisoning downstream build environments.

Detection Guidance

Sigma Rule

title: Potential Erlang ZIP Path Traversal (CVE-2026-47078)
id: 3c9f8a7b-5d7e-4f1a-9c2e-8d6a1b3e7f04
status: experimental
description: Detects ZIP extraction requests or application warnings indicating path traversal attempts through Erlang zip module.
references:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-47078
author: ValtersIT Threat Intelligence Team
date: 2026/06/01
logsource:
    category: application
    product: erlang
detection:
    selection_zip_error:
        - event.message|contains: "zip:extract"
        - event.message|contains: "zip:unzip"
        - event.message|contains: "illegal archive"
    selection_traversal:
        - event.message|contains: "./"
        - event.message|contains: "/../"
        - event.message|contains: "..\\"
    condition: selection_zip_error and selection_traversal
level: high
falsepositives:
    - Legitimate nested directory extraction
    - Malformed but non-malicious ZIP files

YARA Rule

rule CVE_2026_47078_Zip_Traversal {
    meta:
        author = "ValtersIT Threat Intelligence"
        description = "Detects ZIP archives containing path traversal entries targeting Erlang zip module check_dir_level bypass"
        reference = "CVE-2026-47078"
        date = "2026-06-01"
        severity = "high"
    strings:
        $traversal1 = "..\\x\\y" ascii wide
        $traversal2 = "../x/y" ascii wide
        $traversal3 = "../" ascii wide
        $erlang_zip = /(?i)check_dir_level|zip:extract|zip:unzip/
    condition:
        uint16(0) == 0x4B50 and
        2 of ($traversal*) and
        $erlang_zip
}

Suricata IDS Rule

alert http any any -> $HOME_NET any (msg:"ET EXPLOIT Erlang ZIP Path Traversal Attempt (CVE-2026-47078)"; flow:to_server,established; content:"POST"; http_method; content:"multipart/form-data"; http_content_type; content:"|50 4B 03 04|"; http_client_body; content:"|2E 2E 2F|"; http_client_body; content:!"|2E 2E 2F 2E 2E|"; http_client_body; flowbits:set,et_erl_zip_traversal; classtype:attempted-admin; sid:202647078; rev:1; metadata:affected_product Erlang_OTP, attack_target Web_Server, deployment Perimeter, signature_severity Major, created_at 2026_06_01;)

Elastic Detection

sequence by host.id, process.entity_id with maxspan=1m
  [ file where event.action == "write" and
      file.name == "authorized_keys" or
      file.name == "*.php" or
      file.name == "*.conf" ]
  [ file where event.action == "write" and
      file.path : "*..*" and
      not file.path : "*C:\\*" and
      not file.path : "*\\..\\*\\*\\*" ] // normalize window paths

Splunk SPL Query

index=erlang OR index=web
| search (sourcetype="erlang_error" OR sourcetype="erlang_log") 
        (message="*zip:extract*" OR message="*zip:unzip*")
    OR
    (sourcetype="iis" OR sourcetype="access_combined")
        (status=200 form_data="*multipart/form-data*")
| regex message="(?i).*(\.\.\/|\.\.\\)"
| eval malicious_path=if(match(message, "\.\.\/|\.\.\\"), "TRAVERSAL", "NORMAL")
| stats count by host, source, malicious_path
| where malicious_path="TRAVERSAL"

Wazuh OSSEC Rule

<group name="erlang_zip_traversal,">
  <rule id="100078" level="10">
    <decoded>general</decoded>
    <match>\.\.\/|\.\.\\</match>
    <match>zip:extract|zip:unzip</match>
    <description>Erlang zip module path traversal attempt detected (CVE-2026-47078)</description>
    <mitre>
      <id>T1190</id>
    </mitre>
    <group>attack_attempt,</group>
  </rule>
</group>

Mitigation & Patch Guidance

Patch Confidence: 2/4 — CLAIMED (single source, OSV, claims the patch exists; not independently confirmed).

Immediate Mitigations (no patch required)

  1. Validate ZIP entries before calling zip:extract/2: Write a pre-filter in Erlang that iterates over zip:list_dir/1 results and rejects any entry whose path component contains .. or absolute path segments. This effectively blocks the attack without patching.
  2. Use a sandboxed extraction method: Substitute zip:unzip/2 with an external, hardened tool (unzip -d with proper flags) or a pure-Erlang re-implementation that validates paths using normalized absolute path comparison instead of the integer counter.
  3. Restrict the service account privileges: Run the Erlang service under a dedicated low-privilege user with write access limited to the extraction directory only. Use OS-level permissions to prevent writes outside the intended area even if the vulnerability is triggered.
  4. WAF rules: In front of Erlang HTTP APIs, add a web application firewall rule to inspect multipart file uploads for ZIP MIME types and reject any archive containing .. in entry names. This can be done with a rule that decompresses the ZIP and inspects the central directory.

Patch / Upgrade Steps

  1. Upgrade to a fixed version:
    • OTP 27.3.4.15 or later (for the OTP 27 series)
    • OTP 28.5.0.4 or later (for OTP 28)
    • OTP 29.0.4 or later (for OTP 29)
    • Alternatively, upgrade stdlib package to ≥ 6.2.2.4 (OTP 27), ≥ 7.3.0.1 (OTP 28), or ≥ 8.0.3 (OTP 29).
  2. Verify the patch: Since patch confidence is only 2/4, treat the fix as unverified. After upgrading, run a targeted regression test with a crafted ZIP containing ../x/y to confirm the extraction fails with an {error, illegal_archive} return.
  3. Monitor OSV advisories for additional CVE-2026-47078 signals or a vendor advisory from the Erlang/OTP team.

Long-Term Hardening

  1. Adopt strict validation philosophy: Never use a "balance counter" to validate hierarchical paths of untrusted archives. Instead, normalize the full absolute path of each entry destination and verify it is a subpath of the intended extraction root.
  2. Apply defense-in-depth for ZIP/archive parsing: Use an OTP-independent validation step (e.g., Rust or Go utility invoked via port) for extremely high-security environments.
  3. Implement filesystem jails: On Linux, use chroot, systemd socket activation with RootDirectory= or PrivateTmp=, or mount a dedicated volume for extraction. On macOS, use sandbox profiles.
  4. Harden the runtime: Ensure the Erlang service runs as a non-root, non-login user. Apply SELinux/AppArmor policies to confine the Erlang BEAM process to write only within designated directories.
  5. Hunt for indicators: Review historical logs for zip:extract invocation patterns, and manually inspect the extraction directories for files that shouldn't be there — particularly outside the designated extraction root.

References

  1. NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-47078 — Official CVE record, vulnerable software descriptions.
  2. OSV Advisory: https://osv.dev/vulnerability/CVE-2026-47078 — Affected OTP/stdlib versions, patch status, source claims.
  3. Erlang/OTP Security Advisories (mailing list): https://erlang.org/security.html — Official vendor announcements for the OTP project; monitor for the forthcoming patch advisory.
  4. CWE-23 Relative Path Traversal: https://cwe.mitre.org/data/definitions/23.html — Weakness class taxonomy used by this CVE.
  5. ATT&CK T1190 — Exploit Public-Facing Application: https://attack.mitre.org/techniques/T1190/ — Common tactic mapping for upload-based path traversal exploitation.

Threat Actor Campaigns: No in-the-wild exploitation or threat-actor campaign has been publicly associated with CVE-2026-47078 at the time of writing. The EPSS score of 0.00152 (4.8 percentile) indicates that exploitation is plausible but not currently widespread. Organizations should treat this as a high-priority remediation target given the ease of exploitation and the ubiquity of Erlang-based services in messaging, finance, and middleware stacks.

👁️ SHODAN DORKS (THREAT HUNTING)

What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.

erlang
content-type: application/erlang
port:4369 epmd

💣 PoC CODE AVAILABLE

Exploit code for this CVE is tracked in our database. Access poc_code via API Pro.

[ API_PRO ] →
◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2026-47078/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.