CVE-2023-22462 Overview
CVE-2023-22462 is a stored Cross-Site Scripting (XSS) vulnerability affecting the core "Text" plugin in Grafana, an open-source platform for monitoring and observability. The vulnerability was discovered during an internal audit on 2023-01-01 by a member of Grafana's security team. This stored XSS flaw exists due to React's render cycle behavior, which passes unsanitized HTML code through before cleaning it in subsequent cycles and saving to Grafana's database.
The vulnerability requires multiple user interactions for full exploitation. An attacker with Editor role privileges can inject malicious JavaScript into a Text panel. The code executes when another user (potentially with Admin privileges) edits the same Text panel and clicks on "Markdown" or "HTML" rendering options. This attack chain enables vertical privilege escalation, potentially allowing an Editor-level user to compromise Admin accounts.
Critical Impact
Vertical privilege escalation through stored XSS allows attackers with Editor role to potentially compromise Admin accounts by injecting malicious JavaScript that executes when Admins view or edit affected dashboards.
Affected Products
- Grafana versions prior to 9.2.10
- Grafana versions 9.3.x prior to 9.3.4
- All Grafana installations using the core "Text" plugin
Discovery Timeline
- 2023-01-01 - Vulnerability discovered during internal security audit by Grafana security team
- 2023-02-28 - Grafana releases security advisory and patched versions
- 2023-03-02 - CVE-2023-22462 published to NVD
- 2024-11-21 - Last updated in NVD database
Technical Details for CVE-2023-22462
Vulnerability Analysis
This stored XSS vulnerability (CWE-79) exploits a race condition in React's render cycle within Grafana's Text plugin. During the initial render pass, unsanitized HTML content is processed and displayed before the sanitization logic executes in subsequent cycles. While the HTML is eventually cleaned and stored properly in Grafana's database, the brief window during the render cycle allows malicious JavaScript to execute.
The attack requires a multi-step exploitation chain: First, an attacker with Editor role modifies a Text panel to include malicious JavaScript payload. The payload remains dormant until another user opens the panel for editing and selects either "Markdown" or "HTML" rendering mode, at which point the JavaScript executes in the victim's browser context.
Root Cause
The root cause lies in React's asynchronous render cycle handling within the Text plugin component. The PluginHelp component and related markdown rendering logic did not properly sanitize content before the initial render pass. The patch refactored the component from a class-based PureComponent to a functional component with proper async handling using the useAsync hook, ensuring content is sanitized before being rendered to the DOM.
Attack Vector
The attack vector is network-based and requires authenticated access with Editor privileges. The exploitation chain involves:
- Attacker authenticates to Grafana with Editor role
- Attacker modifies a Text panel to inject JavaScript payload
- Victim user with higher privileges (e.g., Admin) accesses the dashboard
- Victim attempts to edit the Text panel and selects Markdown/HTML mode
- Malicious JavaScript executes in victim's browser session
- Attacker can perform actions as the victim, including password changes
// Security patch in public/app/core/components/PluginHelp/PluginHelp.tsx
-import React, { PureComponent } from 'react';
+import React from 'react';
+import { useAsync } from 'react-use';
import { renderMarkdown } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
+import { LoadingPlaceholder } from '@grafana/ui';
interface Props {
- plugin: {
- name: string;
- id: string;
- };
- type: string;
+ pluginId: string;
}
-interface State {
- isError: boolean;
- isLoading: boolean;
- help: string;
-}
+export function PluginHelp({ pluginId }: Props) {
+ const { value, loading, error } = useAsync(async () => {
+ return getBackendSrv().get(`/api/plugins/${pluginId}/markdown/query_help`);
+ }, []);
-export class PluginHelp extends PureComponent<Props, State> {
- state = {
- isError: false,
Source: GitHub Commit db83d5f
Detection Methods for CVE-2023-22462
Indicators of Compromise
- Unexpected JavaScript code within Text panel configurations in Grafana dashboards
- Audit logs showing Editor-role users modifying Text panels with suspicious content containing <script> tags or event handlers
- Dashboard JSON exports containing encoded or obfuscated JavaScript payloads
- User account changes (especially password resets) occurring after Admin users viewed specific dashboards
Detection Strategies
- Enable and monitor Grafana audit logs for Text panel modifications by Editor-role users
- Implement Content Security Policy (CSP) headers to detect and block inline script execution attempts
- Deploy web application firewalls (WAF) to detect XSS payload patterns in dashboard API requests
- Review dashboard configurations for suspicious HTML content or JavaScript in Text panels
Monitoring Recommendations
- Configure alerts for dashboard modifications involving the Text plugin, particularly those containing script elements
- Monitor for unusual authentication patterns following dashboard viewing events
- Implement real-time log analysis for Grafana API endpoints related to plugin content and dashboard editing
- Track privilege changes and password modification events correlated with dashboard access times
How to Mitigate CVE-2023-22462
Immediate Actions Required
- Upgrade Grafana immediately to version 9.2.10 or later for the 9.2.x branch
- Upgrade to version 9.3.4 or later for the 9.3.x branch
- Audit all existing Text panels across dashboards for potentially malicious content
- Review recent Editor-role user activity for suspicious dashboard modifications
- Consider temporarily restricting Text panel editing capabilities until patching is complete
Patch Information
Grafana has released security patches addressing this vulnerability in versions 9.2.10 and 9.3.4. The fix refactors the plugin help component to use proper async content loading with the useAsync hook, ensuring content sanitization occurs before rendering. The patch also corrects the markdown file fallback logic in the backend API.
For detailed patch information, refer to:
Workarounds
- Restrict Editor role assignments to trusted users only until patching can be completed
- Implement additional Content Security Policy headers to mitigate XSS impact: script-src 'self'
- Disable or remove the Text plugin if not required for operations
- Deploy network-level filtering to block common XSS payload patterns in Grafana API traffic
- Require Admin approval for any Text panel modifications in critical dashboards
# Configuration example - Implementing CSP headers in Grafana
# Add to grafana.ini or custom.ini configuration file
[security]
# Enable strict Content Security Policy
content_security_policy = true
# Define CSP directives to mitigate XSS
content_security_policy_template = """
script-src 'self' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
object-src 'none';
frame-ancestors 'self';
"""
# Additional recommended security settings
cookie_secure = true
cookie_samesite = strict
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


