CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27819
9.10.05%

Vikunja's Kamikaze Restore: Zip Slips and Database Wipes

Alon Barad
Alon Barad
Software Engineer

Feb 26, 2026·6 min read·8 visits

PoC Available

Executive Summary (TL;DR)

Vikunja < 2.0.0 contains a 'Zip Slip' vulnerability in its CLI restore command. Malicious backups can overwrite system files. Worse, the code wipes the database *before* validating the backup; if the backup is malformed, the app panics, crashes, and leaves you with an empty database.

A critical vulnerability in Vikunja's restore functionality allows for arbitrary file overwrites via Path Traversal (Zip Slip) and permanent data loss due to improper error handling. The application destructively wipes the existing database before validating the integrity of the backup archive, leading to potential Denial of Service (DoS) or Remote Code Execution (RCE).

The Hook: Task Management or Data Russian Roulette?

Vikunja is the open-source darling for self-hosters who want to organize their lives without handing their data over to Big Tech. It is written in Go, sleek, and generally robust. However, every application has that one closet where they shove the messy code. In Vikunja's case, that closet was the CLI restore command.

The restore function is intended to take a backup ZIP file and reinstate your tasks, lists, and users. Ideally, a restore operation should be atomic: check the backup, prepare the transaction, and only then commit changes. Vikunja took a different approach. It was the digital equivalent of a mover who burns down your current house before checking if the furniture truck actually arrived.

This vulnerability (CVE-2026-27819) isn't just about reading files you shouldn't. It is about a catastrophic failure in logic that combines a classic directory traversal attack (Zip Slip) with a 'Kamikaze' execution flow that can leave a production instance permanently broken and empty.

The Flaw: Trusting the Archive

The vulnerability stems from two distinct but compounding failures in vikunja/pkg/modules/dump/restore.go. The first is blind trust in user input. When processing a ZIP archive, the application iterates through files and checks if they start with database/. If they do, it strips that prefix and uses the rest of the string as the filename for the restore operation.

This is the textbook definition of Zip Slip (CWE-22). The application failed to sanitize the path for directory traversal characters (../). If I hand the application a ZIP file containing an entry named database/../../../../etc/shadow, Vikunja obliges and attempts to write to that location relative to its execution root.

The second flaw is Uncaught Exception (CWE-248) combined with Improper Sequencing. The code attempts to access a slice index (len(ms)-2) without verifying the slice actually has enough elements. If you feed it a malformed or empty backup, the Go runtime panics. Because this panic happens after the database wipe command, the application crashes, the process dies, and your data is gone forever.

The Code: Anatomy of a Wipe

Let's look at the vulnerable logic. It's a masterclass in 'check the wrong thing, then do the dangerous thing'.

// Vulnerable Code Pattern
func Restore(path string) error {
    // 1. OPEN THE ZIP
    z, _ := zip.OpenReader(path)
 
    // 2. WIPE THE DATABASE (The Point of No Return)
    // This runs before we even know if the zip is valid!
    db.WipeEverything()
 
    // 3. ITERATE FILES
    for _, f := range z.File {
        // The Zip Slip:
        // Checks prefix, but doesn't sanitize directory traversal
        if strings.HasPrefix(f.Name, "database/") {
             fileName := strings.TrimPrefix(f.Name, "database/")
             // ... writes to fileName ...
        }
    }
 
    // 4. THE PANIC
    // Accessing slice without bounds check
    // If ms is empty, this crashes the app.
    version := ms[len(ms)-2]
}

The fix introduced in commit 1b3d8dc59cb5f2b759ab0ad2bc9915b993e3cb73 completely restructures this flow. It introduces a strict filename parser:

func parseDbFileName(fname string) (string, bool) {
    // Explicitly forbids slashes and requires .json
    if strings.Contains(fname, "/") || strings.Contains(fname, "\\") {
        return "", false
    }
    if !strings.HasSuffix(fname, ".json") {
        return "", false
    }
    return strings.TrimSuffix(fname, ".json"), true
}

Critically, the patched version now reads the entire backup into memory (with a 500MB cap) and validates every single JSON file before calling db.WipeEverything(). This prevents the DoS scenario effectively.

The Exploit: Slipping and Crashing

Exploiting this requires creating a malicious ZIP file. Standard archiving tools usually prevent you from adding relative paths like ../, so we'd python-script this.

Attack Scenario 1: The Config Overwriter (RCE)

We want to overwrite config.yml to change the database host to a malicious server we control, or perhaps overwrite a binary if permissions allow.

  1. Create a file named config.yml (locally).
  2. Use a Python script to write this file into a ZIP archive with the name database/../../config.yml.
  3. Run vikunja restore malicious.zip.
  4. Result: The application sees the database/ prefix, strips it, and writes the file to ../../config.yml relative to the CWD.

Attack Scenario 2: The Data Wiper (DoS)

This is for the chaotic evil attacker. We simply want to destroy the instance.

  1. Create a ZIP file that is valid enough to open, but contains no migration data (or empty JSONs).
  2. Run vikunja restore broken.zip.
  3. Result:
    • Vikunja calls db.WipeEverything().
    • Database tables are dropped.
    • Vikunja tries to parse migrations, hits the index out of range panic.
    • The app crashes.
    • The admin restarts the app, but the database is empty. The data is lost.

The Impact: Why You Should Care

While this vulnerability requires CLI access (or an admin trigger), the impact is Critical.

Confidentiality & Integrity: The Zip Slip component allows an attacker to overwrite sensitive configuration files or inject code (e.g., via cron jobs or webhooks if they are stored as files). This is a direct path to Remote Code Execution (RCE) depending on the file system permissions of the user running Vikunja.

Availability: The destructive nature of the restore logic is arguably worse for the average user. A corrupted backup file shouldn't result in a total loss of production data. In a worst-case scenario, an automated backup/restore testing pipeline could inadvertently wipe a staging or production database simply because the backup artifact was incomplete.

The Fix: Validate First, Wipe Later

The remediation strategy adopted by the Vikunja team is robust. By separating validation from execution, they moved from a 'Fail-Unsafe' to a 'Fail-Safe' architecture.

For Developers:

  1. Never trust archive file paths. Always sanitize them. Use filepath.Base() or explicit allow-lists.
  2. Transactional Logic. Do not perform irreversible destructive actions (like dropping tables) until you have verified the replacement data is 100% valid.
  3. Bounds Checking. Go's panic on out-of-bounds slice access is a feature, not a bug. Check your len() before you leap.

For Users: Upgrade to v2.0.0 immediately. If you cannot upgrade, treat the restore command as a loaded gun—verify your ZIPs manually and take a snapshot of your VM/DB before running it.

Official Patches

VikunjaGitHub Commit Fix

Fix Analysis (1)

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.05%
Top 100% most exploited

Affected Systems

Vikunja < 2.0.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
Vikunja
Vikunja
< 2.0.02.0.0
AttributeDetail
CWE IDCWE-22 (Path Traversal) & CWE-248 (Uncaught Exception)
Attack VectorLocal (CLI) / Network (if upload allowed)
CVSS9.1 (Critical)
ImpactArbitrary File Overwrite / Permanent Data Loss
Fixed Versionv2.0.0
Exploit StatusProof of Concept (Internal)

MITRE ATT&CK Mapping

T1083File and Directory Discovery
Discovery
T1499Endpoint Denial of Service
Impact
T1565.001Stored Data Manipulation
Impact
CWE-22
Path Traversal

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Vulnerability Timeline

Fix committed
2026-02-24
CVE Published
2026-02-25
v2.0.0 Released
2026-02-25

References & Sources

  • [1]GHSA Advisory
  • [2]Vikunja 2.0.0 Changelog

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.