Vulnerability DatabaseGHSA-j5fr-jm8f-m549

GHSA-j5fr-jm8f-m549: 
JavaScript vulnerability analysis and mitigation

Summary

Any user who can chat with the bot (any member of a Slack/Rocket.Chat/etc. workspace the bot sits in — the command has no permission check) can send:

hubot graf db <uid> apiEndpoint=../../../api/admin/users#

The apiEndpoint token is accepted by the dashboard-request parser because it matches a key of the internal GrafanaDashboardQuery object. That key is otherwise set only from the operator's HUBOT_GRAFANA_API_ENDPOINT env var (d/d-solo). The value is never validated and is interpolated verbatim into the URL path of the rendered-image URL:

const url = new URL(`${this.host}/render/${query.apiEndpoint}/${uid}/`);

new URL() normalizes ../ segments, so the attacker escapes /render/ and controls the whole path of a GET the bot then issues with the bot's Grafana API key attached (Authorization: Bearer …). The fetched body comes back to the chat as an "image" upload (a Slack file or public-read S3 object), so its content reaches the attacker. A trailing # in the injected value pushes the required /<uid>/ into the fragment, so the path ends up exactly as the attacker wrote it.

Details

  • Package: hubot-grafana (npm)
  • Class: Server-Side Request Forgery / URL path injection with credential forwarding (same-origin). CWE-918 (SSRF); contributing CWE-20 (improper input validation of a query override intended to be operator-only).
  • CVSS: 7.7 HIGH, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N, assuming an admin-scoped API key (a setup the plugin documents). With a Viewer-role key the same bug reads only Viewer-visible endpoints, and that floor is CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N = 6.5 MEDIUM.

Source → sink trace

#LocationWhat happens
1src/grafana.js (robot.respond(/(?:grafana|graph|graf) (?:dash|dashboard|db) …/i))Attacker's chat message; the (.*) remainder (e.g. apiEndpoint=../../../api/admin/users#) is passed to bot.sendDashboardChartFromString. No permission check on this handler.
2src/Bot.jsservice.parseToGrafanaDashboardRequest(requestString)
3src/service/GrafanaService.jsRemainder split on spaces; each key=value part is split into partName/partValue. Tainted partName = "apiEndpoint", partValue = "../../../api/admin/users#".
4src/service/GrafanaService.jsif (partName in request.query) { request.query[partName] = partValue; } — apiEndpoint is an own property of GrafanaDashboardQuery (default from HUBOT_GRAFANA_API_ENDPOINT, intended operator-only), so the check passes and the attacker's string overwrites the operator setting with zero validation.
5src/service/GrafanaService.jsgetDashboard(uid) succeeds for any real dashboard UID, then per panel createImageUrl(req.query, …) runs with the tainted apiEndpoint.
6src/grafana-client.js (createImageUrl)Sink (URL): new URL(${this.host}/render/${query.apiEndpoint}/${uid}/). WHATWG URL normalizes the .. segments; with a trailing # the /<uid>/ becomes the fragment and the path is exactly /api/admin/users. Other parameters go through URLSearchParams (encoded) — only apiEndpoint lands in the path.
7src/Bot.js → src/grafana-client.js (download)When an upload path exists (S3 bucket, or a Slack/Rocket.Chat/Telegram adapter — default-on for Slack), fetch(url, { headers: … Authorization: Bearer <HUBOT_GRAFANA_API_KEY> }); the response body is returned as a Buffer.
8src/Bot.js → the configured uploaderThe fetched bytes are uploaded into the chat room — the S3 variant creates a public-read object and posts its URL — delivering the arbitrary-endpoint response to the attacker.

Impact

A chat user with no Grafana credentials crosses the bot's service-credential boundary: they point an authenticated GET at any path on the Grafana origin using the bot's bearer token, and get the raw response back in chat. With an admin-scoped key this exposes Grafana admin API data (settings, user lists, org/service-account information); the bot becomes a read proxy for the Grafana instance, and because the path escapes /render/ completely, for any same-origin route behind the Grafana host.

Patches

Fixed in 7.4.0. Chat input may now set only an explicit allowlist of query keys (width, height, tz, kiosk). Operator-only keys — including apiEndpoint and orgId — are no longer accepted from chat and can be set solely via their HUBOT_GRAFANA_* environment variables.

Workarounds

There is no configuration toggle to disable the behavior in affected versions, so upgrading to 7.4.0 is the fix. To limit impact — before and after upgrading — run the bot with a least-privilege Grafana credential: a Viewer-role API key or service-account token is sufficient to render dashboards and reduces this issue (and this class of issue generally) to read access over only Viewer-visible endpoints. Avoid configuring the bot with an Admin-scoped key.


Source: NVD

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-j5fr-jm8f-m549HIGH7.7
  • JavaScript logoJavaScript
  • hubot-grafana
NoYesOct 29, 2026
GHSA-w658-mh9p-ww8fMEDIUM6.5
  • JavaScript logoJavaScript
  • @backstage/plugin-catalog-backend
NoYesOct 28, 2026
GHSA-q7jr-6fm4-vvhgMEDIUM4.3
  • JavaScript logoJavaScript
  • n8n-mcp
NoYesOct 29, 2026
GHSA-qm7x-j9xp-x3gvLOW3.1
  • JavaScript logoJavaScript
  • n8n-mcp
NoYesOct 29, 2026
GHSA-6v8j-6w28-2w8rMEDIUMN/A
  • JavaScript logoJavaScript
  • pi-subagents
NoYesOct 29, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management