Chartbrew: Private Chart Data Disclosure via Forged Share Tokens

Chartbrew signs and verifies share tokens with the same hard-coded default key used for authentication. An anonymous attacker forges a token and reads any private chart's data, including by enumerating sequential IDs without knowing a share link.

Advisory ID: TP-2026-056
Product: Chartbrew (open-source business-intelligence platform for data visualization, self-hosted)
Vulnerability type: Improper Verification of Cryptographic Signature (CWE-347)
CVE: CVE-2026-85708
CVSS 3.1: 7.5 (High) · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Vendor advisory: GHSA-3chp-cr6f-hp63
Affected versions: <= 5.2.2
Fixed in: not yet released (fix on master)
Reported: 16 July 2026

Summary

Chartbrew is a self-hosted open-source business-intelligence platform for data visualization whose public share and embed tokens are signed and verified with settings.secret (CB_SECRET) as the primary key with no algorithms allow-list (server/controllers/ChartController.js:1343 sign / :1208 verify; server/controllers/ProjectController.js:433). The Chart branch of findBySharePolicy checks only sub.type==="Chart" and sub.id===sharePolicy.entity_id with no project.public/visibility gate and returns chartData. checkFilterAccess accepts the same forged token for POST /project/:project_id/chart/:chart_id/filter using sequential integer IDs only. With the static default CB_SECRET (change_to_random_string, see CVE-2026-85295) — never generated by setUpEncryptionKeys.js — the signing key is public knowledge. An anonymous attacker forges a token and reads any private chart's data, defeating token expiry and revocation permanently once the secret is known.

Root cause

Share and embed tokens are signed with settings.secret (CB_SECRET) at server/controllers/ChartController.js:1343 and verified with jwt.verify(token, settings.secret) and no algorithms allow-list at :1208. The Chart branch of findBySharePolicy enforces only sub.type==="Chart" and sub.id===sharePolicy.entity_id, with no project.public or visibility check, and returns chartData (checkFilterAccess at server/api/ChartRoute.js:348 accepts the same forged token using sequential integer IDs with no visibility gate). CB_SECRET is the shipped default change_to_random_string, never generated by setUpEncryptionKeys.js, so the signing key is public knowledge. The 99999-day token expiry and the absence of secret rotation mean a private share cannot be revoked once the secret is known. Distinct sink and fix from the auth-forge advisory (CVE-2026-85295).

Proof of Concept

# Forge a share token signed with CB_SECRET:
PAYLOAD {"sub":{"type":"Chart","id":5,"sharePolicyId":3}}
KEY     change_to_random_string (HS256)

# Read private chart data via share route, unauthenticated:
GET /chart/share/<share_string>?token=<forged> HTTP/1.1

HTTP/1.1 200 OK
{"chartData":{"SECRET_MARKER":"CB-VERIFY-DATA-7Q9x","revenue":987654}}

# Baseline, no token:
GET /chart/share/<share_string>
HTTP/1.1 400 "Token is missing"

# Read by integer id enumeration, no share link required:
POST /project/26/chart/5/filter?token=<forged> HTTP/1.1
{"filters":[]}

HTTP/1.1 200 OK
{"chartData":{"secretds":{"data":[{"marker":"CB-VERIFY-DATA-7Q9x"}]}}}

Impact

  • Anonymous disclosure of any private chart's data, including values reachable through the chart's query.
  • Fully arbitrary read by integer ID enumeration, with no share link required.
  • Token expiry and revocation permanently defeated once the secret is known.
  • Read-only, single request, no user interaction.

References

Is Something Like This in Your Software?

Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.