Report vulnerabilities privately through GitHub security advisories or the contact information on our website. Don't open public issues for them.
Please verify against the latest release or main before reporting.
Vikunja is a self-hosted to-do app: a Go API, a Vue frontend, and native desktop and mobile apps. One admin usually runs an instance for a small group of users who share projects with each other.
Trust model:
- The admin is fully trusted. They control the config, the database, the OIDC provider, and whatever the server sends to browsers.
- Users are authenticated but don't trust each other. Access to everything (tasks, comments, attachments, buckets, views) comes from project permissions (read, write, admin), granted through user shares, team shares, or link shares.
- Anonymous visitors can only reach login, registration, password reset, link-share authentication, and public instance info.
- One user reading or changing another user's projects, tasks, or anything attached to them.
- A read-only member gaining write or admin permissions.
- Bypassing authentication: passwords, TOTP, OIDC, API tokens, link shares, CalDAV/feed BasicAuth, session refresh.
- Stored XSS through user content (task titles, descriptions, comments, project descriptions) in the frontend or in emails.
- SSRF through outgoing requests (webhooks, avatar downloads, migration imports) while
outgoingrequests.allownonroutableipsis off. - File handling: attachments, avatar uploads, and imports (path traversal, decompression bombs, size limit bypass).
- Resource exhaustion that one unauthenticated request or a cheap authenticated one can trigger.
These come in regularly. Don't report them unless you can show impact beyond what's described here.
User or email enumeration through password reset or login. Registration has to say whether an address is taken, so that information is already public. Reset and login give clear errors on purpose. All unauthenticated routes are rate-limited per IP (ratelimit.noauthlimit, which can't be disabled).
The OAuth2 server accepts unregistered client_ids, has no client secret, or has no consent screen. /oauth/authorize and /oauth/token exist only for Vikunja's own native apps. They implement the public-client flow from RFC 8252: PKCE (S256) is mandatory, and redirect_uri must use a vikunja-* scheme or be a loopback http URL. Public clients can't keep a secret, which is why PKCE exists. A consent screen wouldn't help either: any local app can claim to be Vikunja, and malware on the user's machine can read their tokens anyway.
Things only an admin can do. Examples: malicious config values ending up in the served frontend, enabling outgoingrequests.allownonroutableips and then reaching internal hosts, or enabling OIDC emailfallback with a provider that doesn't verify emails.
SSRF through a configured proxy. Requests sent via outgoingrequests.proxyurl aren't IP-checked, because the proxy resolves the target and filtering is its job. See the webhook docs.
CSRF on CalDAV or feeds. These routes send no CORS headers, and every state-changing CalDAV method is non-simple, so the browser's preflight blocks cross-origin writes. GET requests change nothing, and their responses can't be read cross-origin.
A permission check looks missing in a handler. Permission checks (CanRead, CanUpdate, ...) run before the handler and derive from the parent project or task. Only report this with a request that succeeds against a running instance.
EXIF metadata in attachments. Files are stored exactly as uploaded, on purpose.
Archived projects can still be changed in some ways. Archiving hides projects; it isn't access control. Please open a regular bug report.
Duplicating a project copies its shares. The new owner can change them.
Large per_page values. They're capped by service.maxitemsperpage.
- Include the Vikunja version (from
/api/v1/info). - Include a bash or curl script that reproduces the issue against a fresh instance. Reports without one take much longer to triage.
- Keep it short. We get a lot of these reports and triaging means reading every one of them. Lead with an executive summary that explain the vulnerability and the impact in 1-2 senteces at most.
- If an AI wrote the report, check its claims against a running instance first.
Bugs without security impact belong in public issues.