CVE-2026-102982 Overview
Plane is an open-source project management tool used by development and operations teams. A stored cross-site scripting (XSS) vulnerability [CWE-79] affects versions prior to 1.4.0. The comment_html field in Plane comments fails to sanitize unsafe URL schemes before storage. A project member can inject a crafted link containing an attacker-controlled script into a comment. When another authenticated user selects the link, the script executes in their browser context. The vendor fixed the issue in Plane version 1.4.0 by introducing centralized HTML content validation.
Critical Impact
Authenticated project members can store malicious scripts in comments that execute in other users' browser sessions, enabling session theft, account takeover, and unauthorized actions within the Plane workspace.
Affected Products
- Plane (makeplane/plane) versions prior to 1.4.0
- Self-hosted Plane deployments using vulnerable comment_html serialization
- Plane instances exposing comment and intake issue functionality to project members
Discovery Timeline
- 2026-10-13 - CVE CVE-2026-102982 published to NVD
- 2026-10-13 - Last updated in NVD database
Technical Details for CVE-2026-102982
Vulnerability Analysis
The vulnerability resides in the comment serialization logic within apps/api/plane/api/serializers/issue.py. The original validate method parsed comment_html using lxml.html.fromstring and re-serialized it with html.tostring. This round-trip only verified that the content was parseable HTML. It did not strip dangerous URL schemes such as javascript: from anchor href attributes or other link-bearing elements.
An authenticated project member can submit a comment containing a hyperlink whose target uses a scripting scheme. When another user clicks the rendered link, the browser evaluates the attacker-supplied script in the authenticated Plane origin. This grants access to session cookies, API tokens stored in local storage, and any action the victim can perform in the workspace.
Root Cause
The root cause is missing sanitization of HTML attribute values, specifically URL schemes within link elements. The pre-patch validator relied on structural HTML parsing instead of an allow-list sanitizer. Any attribute content that survived parsing was persisted verbatim and rendered to downstream viewers.
Attack Vector
Exploitation requires network access to the Plane application and low-privileged authenticated access as a project member. The attacker stores a payload in a comment or intake issue description. Exploitation completes when a victim user interacts with the malicious link, satisfying the user interaction requirement in the attack chain.
# Patch excerpt: apps/api/plane/api/serializers/issue.py
exclude = ["comment_stripped", "comment_json"]
def validate(self, data):
- try:
- if data.get("comment_html", None) is not None:
- parsed = html.fromstring(data["comment_html"])
- parsed_str = html.tostring(parsed, encoding="unicode")
- data["comment_html"] = parsed_str
-
- except Exception:
- raise serializers.ValidationError("Invalid HTML passed")
+ if "comment_html" in data and data["comment_html"]:
+ is_valid, error_msg, sanitized_html = validate_html_content(data["comment_html"])
+ if not is_valid:
+ raise serializers.ValidationError({"comment_html": "HTML content is not valid"})
+ if sanitized_html is not None:
+ data["comment_html"] = sanitized_html
return data
# Source: https://github.com/makeplane/plane/commit/0d58adb69d859fc94c43b9d68fadd77e810d5ed1
Detection Methods for CVE-2026-102982
Indicators of Compromise
- Comments or intake issue descriptions containing javascript:, data:, or vbscript: URL schemes in href attributes
- Database rows in the comments table where comment_html contains <script> tags or inline event handlers such as onclick, onerror, or onmouseover
- Unexpected outbound requests from authenticated user browsers to attacker-controlled domains originating from a Plane workspace tab
Detection Strategies
- Query the Plane database for stored comment_html and description_html values matching regex patterns for unsafe URL schemes or script constructs
- Deploy a Content Security Policy (CSP) in report-only mode to log inline script execution attempts within the Plane origin
- Review web server access logs for anomalous referrer chains originating from /comments/ endpoints followed by requests to external domains
Monitoring Recommendations
- Alert on new comment submissions whose payload size or HTML attribute density deviates from baseline user behavior
- Capture browser console errors and CSP violation reports from Plane sessions into a centralized logging pipeline
- Monitor authentication tokens and session cookies for use from unexpected IP addresses shortly after comment interactions
How to Mitigate CVE-2026-102982
Immediate Actions Required
- Upgrade all Plane deployments to version 1.4.0 or later without delay
- Audit existing comment_html and intake description_html records for stored payloads containing unsafe URL schemes or script constructs
- Rotate session secrets and invalidate active sessions for any workspace where malicious comments are identified
- Restrict project membership to trusted users until the patch is applied
Patch Information
The fix is included in Plane v1.4.0. The patch introduces a shared validate_html_content helper in plane.utils.content_validator and applies it to both the comment serializer and the intake issue views. See the GitHub Security Advisory GHSA-6qrq-f73q-r67j, the GitHub Release v1.4.0, the GitHub Commit Overview, and the GitHub Pull Request Discussion.
Workarounds
- Enforce a strict Content Security Policy that disallows inline scripts and restricts script-src to the Plane origin
- Place the Plane application behind a reverse proxy or web application firewall that strips javascript: and data: URL schemes from request bodies targeting comment endpoints
- Temporarily disable comment and intake features for untrusted project members through role restrictions until upgrading
# Upgrade self-hosted Plane deployment to the patched release
git fetch --tags
git checkout v1.4.0
docker compose -f docker-compose.yml pull
docker compose -f docker-compose.yml up -d
# Verify running version
docker compose exec api python -c "import plane; print(plane.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

