CVE-2026-52798: Gogs Stored XSS in .ipynb Notebook Preview
A stored XSS flaw in Gogs lets any user with repository write access embed a javascript: link inside a Jupyter notebook file, which executes arbitrary JavaScript in a viewer's browser when they click
The problem
Gogs versions up to and including 0.14.2 sanitize .ipynb notebook output on the server via POST /-/api/sanitize_ipynb, but then immediately re-render every .nb-markdown-cell element on the client side using the marked() Markdown library with no further sanitization.
This second render pass reconstructs javascript: scheme hyperlinks that the server-side sanitizer had removed. No Content Security Policy is applied to repository file views, so the reconstructed link executes freely when clicked. Any user who can push a .ipynb file to a repository (even a public one) can target any viewer, including admins.
Proof of concept
{
"nbformat": 4,
"nbformat_minor": 2,
"metadata": {},
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[poc](javascript:alert(document.domain))"
]
}
]
}The root cause is a double-render architecture flaw (CWE-79). The server sanitizer runs once and strips dangerous URLs, but view_file.tmpl then calls $(markdown).html(marked($(markdown).html(), {renderer: renderer})) for every .nb-markdown-cell, handing raw HTML back to marked() which faithfully regenerates the javascript: href from the Markdown source text that survived sanitization.
The patch (commit 17b168b) removes this unsanitized client-side re-render pass, or rewrites it to strip dangerous URL schemes before writing back to the DOM, closing the bypass. No CSP was present on file view pages to provide a safety net.
The fix
Upgrade Gogs to version 0.14.3 or later. The patch commit 17b168b11ca759a7550e1f4bbd68bbde14db7785 (PR #8319) removes the unsafe client-side marked() re-render of .nb-markdown-cell content. No configuration workaround exists for older versions.