GHSA-4FXQ-2X3X-6XQX

Vulnerability from github – Published: 2026-04-16 21:08 – Updated: 2026-04-24 20:48
VLAI
Summary
zrok: Reflected XSS in GitHub OAuth callback via unsanitized refreshInterval error rendering
Details

Summary The proxyUi template engine uses Go's text/template (which performs no HTML escaping) instead of html/template. The GitHub OAuth callback handlers in both publicProxy and dynamicProxy embed the attacker-controlled refreshInterval query parameter verbatim into an error message when time.ParseDuration fails, and render that error unescaped into HTML. An attacker can deliver a crafted login URL to a victim; after the victim completes the GitHub OAuth flow, the callback page executes arbitrary JavaScript in the OAuth server's origin.

  • Attack Vector: Network — the attack is delivered as a crafted URL over the internet.
  • Attack Complexity: Low — no race conditions or special environment prerequisites.
  • Privileges Required: None — the attacker needs no account on the zrok instance.
  • User Interaction: Required — the victim must click the crafted link and complete the GitHub OAuth flow.
  • Scope: Changed — the injected script executes in the OAuth server's origin, not the victim's share origin.
  • Confidentiality Impact: Low — the script runs in the OAuth server origin after a failed flow; no session cookie is set at this point, limiting what can be exfiltrated to what is visible in the DOM and what can be requested from the OAuth server.
  • Integrity Impact: Low — the script can initiate new OAuth flows or submit forms on behalf of the victim in the OAuth server origin.
  • Availability Impact: None.

Affected Components

  • endpoints/proxyUi/template.go — init() / WriteTemplate (lines 8, 18, 99) — text/template used for HTML rendering
  • endpoints/proxyUi/template.html — line 119 — {{ .Error }} in HTML without escaping
  • endpoints/publicProxy/providerGithub.go — login callback closure (lines 93, 128, 130)
  • endpoints/dynamicProxy/providerGithub.go — loginHandler() (lines 110, 146, 148)
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/openziti/zrok"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.1.11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/openziti/zrok/v2"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.0.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-40302"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-16T21:08:55Z",
    "nvd_published_at": "2026-04-17T21:16:34Z",
    "severity": "MODERATE"
  },
  "details": "**Summary**\nThe proxyUi template engine uses Go\u0027s text/template (which performs no HTML escaping) instead of html/template. The GitHub OAuth callback handlers in both publicProxy and dynamicProxy embed the attacker-controlled refreshInterval query parameter verbatim into an error message when time.ParseDuration fails, and render that error unescaped into HTML. An attacker can deliver a crafted login URL to a victim; after the victim completes the GitHub OAuth flow, the callback page executes arbitrary JavaScript in the OAuth server\u0027s origin.\n\n- Attack Vector: Network \u2014 the attack is delivered as a crafted URL over the internet.\n- Attack Complexity: Low \u2014 no race conditions or special environment prerequisites.\n- Privileges Required: None \u2014 the attacker needs no account on the zrok instance.\n- User Interaction: Required \u2014 the victim must click the crafted link and complete the GitHub OAuth flow.\n- Scope: Changed \u2014 the injected script executes in the OAuth server\u0027s origin, not the victim\u0027s share origin.\n- Confidentiality Impact: Low \u2014 the script runs in the OAuth server origin after a failed flow; no session cookie is set at this point, limiting what can be exfiltrated to what is visible in the DOM and what can be requested from the OAuth server.\n- Integrity Impact: Low \u2014 the script can initiate new OAuth flows or submit forms on behalf of the victim in the OAuth server origin.\n- Availability Impact: None.\n\n**Affected Components**\n\n- endpoints/proxyUi/template.go \u2014 init() / WriteTemplate (lines 8, 18, 99) \u2014 text/template used for HTML rendering\n- endpoints/proxyUi/template.html \u2014 line 119 \u2014 {{ .Error }} in HTML without escaping\n- endpoints/publicProxy/providerGithub.go \u2014 login callback closure (lines 93, 128, 130)\n- endpoints/dynamicProxy/providerGithub.go \u2014 loginHandler() (lines 110, 146, 148)",
  "id": "GHSA-4fxq-2x3x-6xqx",
  "modified": "2026-04-24T20:48:45Z",
  "published": "2026-04-16T21:08:55Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/openziti/zrok/security/advisories/GHSA-4fxq-2x3x-6xqx"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40302"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/openziti/zrok"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openziti/zrok/releases/tag/v2.0.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "zrok: Reflected XSS in GitHub OAuth callback via unsanitized refreshInterval error rendering"
}



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…