GHSA-JQ8V-RMF6-65JW

Vulnerability from github – Published: 2026-06-22 23:58 – Updated: 2026-07-21 13:26
VLAI
Summary
Gogs has Stored XSS in `.ipynb` Preview
Details

Summary

Although .ipynb previews are sanitized on the server side via /-/api/sanitize_ipynb, the inserted content is re-rendered on the client side without sanitization using marked() on elements with the .nb-markdown-cell class. During this process, links containing schemes such as javascript: can be regenerated.

As a result, when a victim views an attacker-crafted .ipynb file and clicks the link, arbitrary JavaScript is executed in the Gogs origin, leading to a click-based Stored XSS.

Details

After the rendered output of a .ipynb file is sanitized via /-/api/sanitize_ipynb and inserted into the DOM, only the Markdown cell portions are re-rendered using marked() and overwritten in the DOM. During this process, links with the javascript: scheme can be regenerated.

templates/repo/view_file.tmpl:42–71

{{else if .IsIPythonNotebook}}
  <script>
    $.getJSON("{{.RawFileLink}}", null, function(notebook_json) {
      var notebook = nb.parse(notebook_json);
      var rendered = notebook.render();
      $.ajax({
        type: "POST",
        url: '{{AppSubURL}}/-/api/sanitize_ipynb',
        data: rendered.outerHTML,
        processData: false,
        contentType: false,
      }).done(function(data) {
        $("#ipython-notebook").append(data);
        $("#ipython-notebook code").each(function(i, block) {
          $(block).addClass("py").addClass("python");
          hljs.highlightBlock(block);
        });

        // Overwrite image method to append proper prefix to the source URL
        var renderer = new marked.Renderer();
        var context = '{{.RawFileLink}}';
        context = context.substring(0, context.lastIndexOf("/"));
        renderer.image = function (href, title, text) {
          return `<img src="${context}/${href}"`
        };
        $("#ipython-notebook .nb-markdown-cell").each(function(i, markdown) {
          $(markdown).html(marked($(markdown).html(), {renderer: renderer}));
        });
      });
    });
  </script>

While regular HTML pages (including .ipynb preview pages) are served without a Content Security Policy (CSP), CSP headers are applied only to attachment delivery routes.

internal/cmd/web.go:323

c.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")

Steps to Reproduce

  1. As the attacker, add and push/commit a .ipynb file containing a javascript: link in a Markdown cell to a repository.

  2. Example (PoC):

    json { "nbformat": 4, "nbformat_minor": 2, "metadata": {}, "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[poc](javascript:alert(document.domain))" ] } ] }

  3. The victim opens the file on Gogs (e.g., /<user>/<repo>/src/<branch>/poc.ipynb). image

  4. When the victim clicks the poc link displayed in the preview, alert(document.domain) is executed in the same Gogs origin. image

Minimum Required Privileges

  • Attacker: Ability to place a .ipynb file as a regular (non-admin) user

  • For example: a general user who can create a public repository and add files.

  • Or: write access (collaborator, etc.) to an existing repository that the victim will view.
  • Victim: Permission to view the repository (a click is required).

Impact

  • Unauthorized actions performed with the victim’s account privileges (e.g., repository settings changes, Issue operations,誘導 to token creation).
  • Theft of information accessible to the victim (repository/Issue/Wiki contents, tokens exposed in page context).
  • If the victim is an administrator, the impact may escalate to instance-wide configuration changes and user management.
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.14.2"
      },
      "package": {
        "ecosystem": "Go",
        "name": "gogs.io/gogs"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.14.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-52798"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-22T23:58:46Z",
    "nvd_published_at": "2026-06-24T21:16:55Z",
    "severity": "HIGH"
  },
  "details": "# Summary\n\nAlthough `.ipynb` previews are sanitized on the server side via `/-/api/sanitize_ipynb`, the inserted content is **re-rendered on the client side without sanitization** using `marked()` on elements with the `.nb-markdown-cell` class. During this process, links containing schemes such as `javascript:` can be regenerated.\n\nAs a result, when a victim views an attacker-crafted `.ipynb` file and clicks the link, **arbitrary JavaScript is executed in the Gogs origin**, leading to a click-based Stored XSS.\n\n# Details\n\nAfter the rendered output of a `.ipynb` file is sanitized via `/-/api/sanitize_ipynb` and inserted into the DOM, **only the Markdown cell portions are re-rendered using `marked()` and overwritten in the DOM**. During this process, links with the `javascript:` scheme can be regenerated.\n\n`templates/repo/view_file.tmpl:42\u201371`\n\n```html\n{{else if .IsIPythonNotebook}}\n  \u003cscript\u003e\n    $.getJSON(\"{{.RawFileLink}}\", null, function(notebook_json) {\n      var notebook = nb.parse(notebook_json);\n      var rendered = notebook.render();\n      $.ajax({\n        type: \"POST\",\n        url: \u0027{{AppSubURL}}/-/api/sanitize_ipynb\u0027,\n        data: rendered.outerHTML,\n        processData: false,\n        contentType: false,\n      }).done(function(data) {\n        $(\"#ipython-notebook\").append(data);\n        $(\"#ipython-notebook code\").each(function(i, block) {\n          $(block).addClass(\"py\").addClass(\"python\");\n          hljs.highlightBlock(block);\n        });\n\n        // Overwrite image method to append proper prefix to the source URL\n        var renderer = new marked.Renderer();\n        var context = \u0027{{.RawFileLink}}\u0027;\n        context = context.substring(0, context.lastIndexOf(\"/\"));\n        renderer.image = function (href, title, text) {\n          return `\u003cimg src=\"${context}/${href}\"`\n        };\n        $(\"#ipython-notebook .nb-markdown-cell\").each(function(i, markdown) {\n          $(markdown).html(marked($(markdown).html(), {renderer: renderer}));\n        });\n      });\n    });\n  \u003c/script\u003e\n```\n\nWhile **regular HTML pages (including `.ipynb` preview pages)** are served **without a Content Security Policy (CSP)**, CSP headers are applied **only to attachment delivery routes**.\n\n`internal/cmd/web.go:323`\n\n```go\nc.Header().Set(\"Content-Security-Policy\", \"default-src \u0027none\u0027; style-src \u0027unsafe-inline\u0027; sandbox\")\n```\n\n\n# Steps to Reproduce\n\n1. As the attacker, add and push/commit a `.ipynb` file containing a `javascript:` link in a Markdown cell to a repository.\n\n   * Example (PoC):\n\n     ```json\n     {\n       \"nbformat\": 4,\n       \"nbformat_minor\": 2,\n       \"metadata\": {},\n       \"cells\": [\n         {\n           \"cell_type\": \"markdown\",\n           \"metadata\": {},\n           \"source\": [\n             \"[poc](javascript:alert(document.domain))\"\n           ]\n         }\n       ]\n     }\n     ```\n\n2. The victim opens the file on Gogs (e.g., `/\u003cuser\u003e/\u003crepo\u003e/src/\u003cbranch\u003e/poc.ipynb`).\n\u003cimg width=\"2386\" height=\"1218\" alt=\"image\" src=\"https://github.com/user-attachments/assets/b0d93fd8-c5ca-4058-8af0-98dee590d3ad\" /\u003e\n\n3. When the victim clicks the `poc` link displayed in the preview, `alert(document.domain)` is executed in the same Gogs origin.\n\u003cimg width=\"2390\" height=\"1388\" alt=\"image\" src=\"https://github.com/user-attachments/assets/0eb6ebe8-632c-4a41-8a11-46471514b4c4\" /\u003e\n\n# Minimum Required Privileges\n\n* **Attacker**: Ability to place a `.ipynb` file as a **regular (non-admin) user**\n\n  * For example: a general user who can create a public repository and add files.\n  * Or: write access (collaborator, etc.) to an existing repository that the victim will view.\n* **Victim**: Permission to view the repository (a click is required).\n\n# Impact\n\n* Unauthorized actions performed with the victim\u2019s account privileges (e.g., repository settings changes, Issue operations,\u8a98\u5c0e to token creation).\n* Theft of information accessible to the victim (repository/Issue/Wiki contents, tokens exposed in page context).\n* If the victim is an administrator, the impact may escalate to instance-wide configuration changes and user management.",
  "id": "GHSA-jq8v-rmf6-65jw",
  "modified": "2026-07-21T13:26:45Z",
  "published": "2026-06-22T23:58:46Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/gogs/gogs/security/advisories/GHSA-jq8v-rmf6-65jw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-52798"
    },
    {
      "type": "WEB",
      "url": "https://github.com/gogs/gogs/pull/8319"
    },
    {
      "type": "WEB",
      "url": "https://github.com/gogs/gogs/commit/17b168b11ca759a7550e1f4bbd68bbde14db7785"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/gogs/gogs"
    },
    {
      "type": "WEB",
      "url": "https://github.com/gogs/gogs/releases/tag/v0.14.3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Gogs has Stored XSS in `.ipynb` Preview"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…