This is less a front-door master key than a badly placed mail slot that only matters if the room behind it is already reachable
CVE-2026-28795 is a path traversal flaw in OpenChatBI's save_report tool. In vulnerable builds <=0.2.1, the code strips only leading dots from the file_format parameter and then concatenates it into the output filename, so values like /../../... can escape the intended report directory and turn a report export into an arbitrary file write. The fix landed in 0.2.2, which replaced the weak sanitization with a strict allowlist of supported extensions.
The vendor-style 9.8 framing overstates real enterprise risk. The primitive is dangerous, but the exploitable population is much smaller than a generic pre-auth internet service: this is a niche self-hosted BI/LLM app, many deployments are internal, and turning arbitrary file write into full RCE usually needs a second condition such as write access to a Python import path, startup path, or another executable location. That keeps this in HIGH, not CRITICAL.
4 steps from start to impact.
Reach an exposed OpenChatBI chat or API surface
- A vulnerable OpenChatBI instance
<=0.2.1is deployed - The attacker can reach the chat/API surface that can trigger
save_report - The deployment is not isolated behind VPN, SSO, IP allowlisting, or internal-only routing
- OpenChatBI is a niche OSS package, not a default enterprise platform
- Many BI assistants are only reachable on internal networks
- There is no reliable internet census fingerprint showing broad exposure
Coerce the LLM to call save_report with traversal input
save_report with a malicious file_format, effectively using the agent as the delivery vehicle.- The deployment exposes
save_reportto the agent workflow - The model accepts attacker-controlled prompts or content
- There is no prompt-layer validation or server-side schema enforcement beyond the vulnerable code
- Some deployments may not expose the reporting tool in all workflows
- Application owners may already constrain tools by role or workflow
- Prompt attack reliability varies by model behavior and guardrails
../, /../, or \..\ inside file_format.Abuse path traversal for arbitrary file write
file_format.lstrip(".") removes only leading dots and does not block separators or traversal sequences. The generated filename preserves malicious path segments, allowing writes outside the configured report directory.- The OpenChatBI process has filesystem write permissions to the target path
- The underlying OS path semantics allow the traversal string to resolve as intended
- Least-privilege service accounts reduce writable targets
- Containers with read-only roots or narrow writable volumes sharply cut blast radius
- SELinux/AppArmor/FIM can expose or block unusual writes
Upgrade file write into code execution or persistence
__init__.py, or on Windows, writing to startup locations or PowerShell profile paths. That is plausible, but it is not automatic: the target path must be writable and later executed or imported.- A writable import path, startup folder, cron path, profile path, or equivalent execution sink exists
- The file is later loaded by the application, Python runtime, or operating system
- Many production containers do not permit writes to application code paths
- A restart, import event, or operator action may be required before payload execution
- Wrong target selection degrades impact to simple file corruption or defacement
The supporting signals.
| In-the-wild status | No confirmed active exploitation found in reviewed sources. RAXE explicitly noted *no known exploitation in the wild* as of 2026-03-10. |
|---|---|
| KEV status | Not KEV-listed in the reviewed material. Treat that as a meaningful downgrade signal versus true internet fire drills. |
| EPSS | 0.00089 on 2026-05-30, roughly the 25.35th percentile per FIRST. That's low, and it matches the limited exposure story. |
| PoC availability | There is public reproduction detail in GitHub issue #10, including a described LLM-manipulation path and example impact. That is enough for copycat work even without a polished exploit repo. |
| Affected versions | openchatbi <= 0.2.1 per GHSA and NVD. |
| Fixed version | Upgrade to 0.2.2. The patch commit 372a7e8 replaced lstrip(".") handling with an explicit allowlist: md, csv, txt, json, html, xml. |
| CVSS vector reality check | Vendor/NVD-style AV:N/AC:L/PR:N/UI:N describes the code path in isolation, but it ignores deployment friction: reachable population is narrow, and reliable RCE usually needs a writable execution sink after the arbitrary file write. |
| Exposure population | OpenChatBI is a niche OSS package with about 566 GitHub stars in the reviewed repo snapshot and sample self-hosted UIs, not a mass-market enterprise appliance. That lowers the expected externally exposed population. |
| Scanner / census coverage | Version-based package or image scanning should work. Internet census visibility is weak because OpenChatBI often presents through generic Python web stacks; no trustworthy Shodan/Censys count was found. |
| Disclosure / reporter | Public GitHub advisory published 2026-03-02; NVD published the CVE on 2026-03-06. The public issue credits the bug report to @guokailiang0925. |
noisgate verdict.
The decisive downgrade factor is deployment friction: this is a dangerous arbitrary file write in a niche self-hosted BI assistant, not a proven internet-wide pre-auth RCE on a ubiquitous edge product. The exploit chain gets materially harder in real environments because many deployments are internal and full code execution usually requires a second writable execution sink after the initial file write.
Why this verdict
- Start at 9.8, then cut for population. The vendor/NVD baseline assumes a generic unauthenticated network service, but OpenChatBI is a niche self-hosted package with a much smaller exposed install base than mainstream enterprise middleware.
- Cut again for attacker position. In many real deployments this requires access to an internal BI assistant or developer-run demo surface, which implies a narrower reachable population than edge-facing software.
- Keep it HIGH because the primitive is still ugly. Arbitrary file write from a remote prompt/tool path is serious, and where the service account can touch executable paths the impact can absolutely become RCE or persistence.
Why not higher?
There is no KEV entry, no credible in-the-wild exploitation evidence, and EPSS is low. More importantly, the chain from file write to full system compromise is conditional: writable execution paths, permissive filesystem rights, and sometimes a restart or import event are all real friction points that stop this from being a straight CRITICAL in most enterprises.
Why not lower?
This is still a remote arbitrary file write on the application host, not a cosmetic bug. Even if code execution does not materialize, unauthorized file creation or overwrite on an analytics server can damage integrity, create persistence, or poison downstream workflows, so MEDIUM would be too forgiving.
What to do — in priority order.
- Constrain filesystem writes — Run the OpenChatBI service account with write access only to the intended report directory and deploy this within the noisgate mitigation SLA for a HIGH finding, meaning within 30 days. This is the single best compensating control because it converts a broad arbitrary file write into a contained report-write failure.
- Make the application root read-only — If containerized, use a read-only root filesystem and mount only a narrow writable volume for report output; if not containerized, apply equivalent OS ACLs within 30 days. This directly breaks the most dangerous post-write step: overwriting importable code or startup paths.
- Restrict reachability — Put OpenChatBI behind VPN, SSO, reverse-proxy auth, or IP allowlisting within 30 days if it is currently reachable from untrusted networks. The biggest severity reducer in practice is shrinking who can even reach the tool-calling surface.
- Log and alert on tool arguments — Capture
save_reportinvocations and alert onfile_formatvalues containing/,\,.., or unsupported extensions within 30 days. This gives you early delivery-stage visibility before the arbitrary write lands. - Enable FIM on code and startup paths — Deploy file integrity monitoring for the OpenChatBI package tree, startup folders, profiles, and report directories within 30 days. That will catch the step that matters operationally: unexpected writes outside the normal export path.
- A generic perimeter WAF doesn't reliably solve this, because the exploit can arrive as model prompt content and become malicious only when the agent calls
save_report. - Relying on anti-malware alone is weak; many successful abuse cases are just text file overwrites until a later import or startup event triggers execution.
- Blocking
.characters is not enough; the vulnerable logic already stripped leading dots and still allowed traversal through path separators.
Crowdsourced verification payload.
Run this on the target host, container, golden image, or CI job that builds the OpenChatBI environment. Invoke it with python3 verify_openchatbi_cve_2026_28795.py or point it at a source tree with python3 verify_openchatbi_cve_2026_28795.py /opt/openchatbi; no admin rights are required, but you need read access to the Python environment or source files.
#!/usr/bin/env python3
# verify_openchatbi_cve_2026_28795.py
# Detects whether OpenChatBI is vulnerable to CVE-2026-28795.
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import os
import re
import sys
from pathlib import Path
try:
from importlib import metadata as importlib_metadata
except Exception:
import importlib_metadata # type: ignore
def parse_version(v):
parts = re.findall(r"\d+", v or "")
if not parts:
return tuple()
return tuple(int(x) for x in parts[:4])
def version_leq(a, b):
la = list(a)
lb = list(b)
while len(la) < len(lb):
la.append(0)
while len(lb) < len(la):
lb.append(0)
return tuple(la) <= tuple(lb)
def inspect_file(path: Path):
try:
text = path.read_text(encoding="utf-8", errors="ignore")
except Exception:
return None
has_lstrip = 'file_format.lstrip(".")' in text or "file_format.lstrip('.')" in text
has_allowlist = "allowed_formats" in text and "Unsupported file format" in text
if has_allowlist and not has_lstrip:
return "PATCHED"
if has_lstrip and not has_allowlist:
return "VULNERABLE"
if has_lstrip and has_allowlist:
return "UNKNOWN"
return None
def candidate_paths(root: Path):
paths = [
root / "openchatbi" / "tool" / "save_report.py",
root / "tool" / "save_report.py",
root / "save_report.py",
]
return [p for p in paths if p.exists()]
def main():
target = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else None
# 1) Source tree inspection if a path argument is provided
if target:
if target.is_file():
result = inspect_file(target)
if result == "PATCHED":
print("PATCHED")
sys.exit(0)
if result == "VULNERABLE":
print("VULNERABLE")
sys.exit(1)
elif target.is_dir():
for p in candidate_paths(target):
result = inspect_file(p)
if result == "PATCHED":
print("PATCHED")
sys.exit(0)
if result == "VULNERABLE":
print("VULNERABLE")
sys.exit(1)
# 2) Installed package version check
try:
version = importlib_metadata.version("openchatbi")
pv = parse_version(version)
if pv:
if version_leq(pv, (0, 2, 1)):
print("VULNERABLE")
sys.exit(1)
if pv >= (0, 2, 2):
print("PATCHED")
sys.exit(0)
except Exception:
pass
# 3) Import path code inspection as fallback
try:
import openchatbi # type: ignore
pkg_root = Path(openchatbi.__file__).resolve().parent
for p in candidate_paths(pkg_root.parent):
result = inspect_file(p)
if result == "PATCHED":
print("PATCHED")
sys.exit(0)
if result == "VULNERABLE":
print("VULNERABLE")
sys.exit(1)
except Exception:
pass
print("UNKNOWN")
sys.exit(2)
if __name__ == "__main__":
main()
If you remember one thing.
<=0.2.1 installs to 0.2.2 within 180 days per the noisgate remediation SLA; there is no immediate-hours override here because there is no KEV listing or credible active exploitation evidence in the reviewed sources.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.