← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-28797 · CWE-20 · Disclosed 2026-04-03

RAGFlow is an open-source RAG

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a guest badge that quietly opens the server room

CVE-2026-28797 is an authenticated server-side template injection in RAGFlow Agent workflow components, specifically Text Processing (StringTransform) and Message. In RAGFlow 0.24.0 and earlier, those components render user-controlled Jinja2 templates without sandboxing, so a low-privileged user can turn a harmless-looking template field into OS command execution on the RAGFlow server.

The vendor's HIGH call is directionally right on impact but a little hot if you care about enterprise patch queues. This is not pre-auth internet spray-and-pray RCE: the attacker needs a valid account and access to Agent workflow features, which sharply narrows exposed population; but the default self-registration path and the fact that *any* authenticated user can jump straight to server command execution keep it solidly in HIGH rather than MEDIUM.

"Big impact, but not a perimeter fire: this is post-auth RCE with real default-path friction reduced by self-registration"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Get a basic RAGFlow account

The attacker needs authenticated access to the RAGFlow web UI or API. GitHub's advisory states self-registration is enabled by default via REGISTER_ENABLED=1, so on casually exposed deployments this can be as simple as creating a normal user instead of stealing one.
Conditions required:
  • RAGFlow is reachable from the attacker's network position
  • The attacker can self-register or already has valid credentials
  • Agent workflow features are available to the authenticated user
Where this breaks in practice:
  • Many enterprise deployments put RAGFlow behind SSO, VPN, or reverse proxies
  • Some shops disable self-registration or do not expose the app publicly
  • This prerequisite already implies a post-initial-access or valid-user scenario when registration is closed
Detection/coverage: External vuln scanners often miss this step because the issue is authenticated and feature-path specific; identity telemetry and app auth logs are more useful than perimeter scanning.
STEP 02

Plant a Jinja2 SSTI payload in an Agent component

Using the built-in Agent editor, the attacker adds a Text Processing or Message node and inserts a malicious Jinja2 expression such as the advisory's cycler.__init__.__globals__.os.popen(...) payload. The vulnerable code path uses unsandboxed jinja2.Template, so template syntax becomes code-reachable rather than data-only.
Conditions required:
  • Authenticated user can create or edit an Agent flow
  • Vulnerable code is present in agent/component/string_transform.py or agent/component/message.py
Where this breaks in practice:
  • Requires knowledge of the Agent workflow UI and which nodes render templates
  • If the deployment already moved to sandboxed rendering in v0.25.0+, this breaks
Detection/coverage: SAST/SCA can identify vulnerable versions and code patterns; DAST coverage is weak because the exploit lives behind authenticated business logic.
STEP 03

Trigger render and execute commands

The attacker runs the Agent flow and the backend renders the malicious template. From there os.popen() executes with the privileges of the RAGFlow server process, turning a normal user workflow action into host-level command execution in the application context.
Conditions required:
  • The crafted workflow is executed
  • The server process can spawn commands through Python runtime access
Where this breaks in practice:
  • EDR can sometimes catch suspicious child processes like bash, sh, or python spawned by the app
  • Container hardening, seccomp, or restricted runtime privileges can limit follow-on damage even if code execution lands
Detection/coverage: Host telemetry is the best control here: child-process creation from the RAGFlow service, shell invocation from Python, and unusual outbound connections from the container/host.
STEP 04

Harvest secrets and pivot inside the stack

The advisory explicitly calls out access to conf/service_conf.yaml, environment variables, and service credentials for MySQL, Redis, MinIO, and Elasticsearch. That means the practical blast radius is not just the web app process; it often becomes database access, document theft, API key exposure, and lateral movement into adjacent internal services.
Conditions required:
  • RAGFlow stores usable credentials locally or in environment variables
  • Backend services are reachable from the compromised app host or container
Where this breaks in practice:
  • Segmentation and secret externalization reduce the value of app compromise
  • Read-only service accounts and isolated data-plane services can blunt the pivot
Detection/coverage: Look for reads of conf/service_conf.yaml, bulk DB access from the app tier, unusual Redis/Elasticsearch/MinIO connections, and egress after Agent workflow executions.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo public active-exploitation evidence found in the reviewed authoritative sources, and CISA KEV does not list this CVE as of 2026-05-30.
PoC availabilityYes, effectively public. The GitHub advisory includes full reproduction steps, working payloads, and a demo video, which is enough for immediate copy-paste weaponization.
EPSSUser-supplied EPSS is 0.00102 (~0.10%), which is low. Primary FIRST reference confirms EPSS is a daily probability signal, but the exact percentile for this CVE was not directly verifiable from reviewed primary sources.
KEV statusNot KEV-listed. That materially lowers urgency versus edge-device or mass-exploitation bugs.
CVSS vector readoutCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H means network reachable, easy to exploit, but requires valid low privileges. The whole reassessment turns on that PR:L prerequisite.
Affected versionsAuthoritative sources say RAGFlow 0.24.0 and earlier are affected, in Agent workflow StringTransform and Message components.
Fixed versionThe advisory said no public patch at publication. Upstream code and release timing indicate the sandboxed fix is present by v0.25.0; no distro backport guidance was found.
Exposure realityThis is not a firewall-class product with huge edge prevalence. Public web search of Shodan facet pages shows only low-count indexed banners titled RAGFlow, suggesting limited direct internet exposure; exact counts fluctuate and this is an inference from public scan pages.
Disclosure timelineGitHub advisory published 2026-04-01; NVD published 2026-04-03; NVD last modified 2026-04-22.
Reporter / sourceThe authoritative disclosure path is GitHub Security Advisory GHSA-vvwj-fvwh-4whx, published by yingfeng for infiniflow/ragflow.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (7.6/10)

The decisive factor is the authenticated-user requirement: this is not a perimeter bug, it is a valid-user-to-server-compromise bug. That said, the blast radius after successful exploitation is large because RAGFlow commonly holds API keys, database credentials, and access to internal data services.

HIGH Technical impact once exploited
MEDIUM Real-world exposure and prevalence assumptions
MEDIUM Patched-version mapping to `v0.25.0` from upstream code and release timing

Why this verdict

  • Downgrade from vendor 8.8 for PR:L: requiring authenticated remote access means the attacker is not starting from the open internet unless self-registration is enabled or creds are already compromised.
  • Exposure population is narrower: RAGFlow is popular in open-source circles, but it is not an internet-edge staple, and public scan artifacts suggest only limited direct exposure compared with mass-targeted platforms.
  • Upgrade pressure remains because blast radius is ugly: once inside, the attacker can pivot from app-level template injection to command execution, secret theft, data access, and likely control of backing services.

Why not higher?

This is not pre-auth RCE and not a KEV-listed or publicly observed mass-exploitation event. The chain assumes either valid credentials or a registration path, and many enterprise deployments should already put this app behind SSO, VPN, or restricted admin access.

Why not lower?

The permission bar is low: GitHub's advisory says *any authenticated user* can reach the vulnerable workflow components, and self-registration is enabled by default. Once triggered, the vulnerability is not a narrow tenant-only issue; it can expose host commands, service credentials, and all tenant data reachable by the server.

05 · Compensating Control

What to do — in priority order.

  1. Disable self-registration — If you cannot patch immediately, remove the easiest attacker on-ramp by setting REGISTER_ENABLED=0 or otherwise closing public signup. For a HIGH verdict, deploy this compensating control within 30 days; do it first on any internet-reachable instance.
  2. Put RAGFlow behind identity and network gates — Force access through SSO, VPN, IP allowlists, or a private reverse proxy so this stays an internal-user problem instead of an internet problem. For a HIGH verdict, apply this within 30 days, prioritizing exposed or partner-accessible deployments.
  3. Restrict Agent workflow access — Remove Agent creation/edit rights from ordinary users and confine those functions to trusted admins or service users. This directly cuts the exploit path because the vulnerable components sit inside the Agent workflow feature set; enforce within 30 days.
  4. Harden the runtime — Run RAGFlow with least privilege, tight container profiles, minimal mounted secrets, and segmentation to MySQL/Redis/MinIO/Elasticsearch. This will not prevent code execution, but it can cap post-exploitation blast radius; implement within 30 days where patching is delayed.
  5. Alert on app-to-shell behavior — Tune EDR or container runtime telemetry to flag shells, os.popen, reverse shells, or unusual outbound connections from the RAGFlow process/container. This is a detection-oriented compensating control and should also be in place within 30 days for lingering vulnerable nodes.
What doesn't work
  • A generic WAF is not enough; the exploit sits in authenticated business logic and uses legitimate workflow fields rather than a clean unauthenticated HTTP exploit string.
  • Relying on network-only vuln scanning will miss too much because the vulnerable path requires login and specific Agent workflow interactions.
  • Simply rotating LLM provider API keys does not solve the core issue; the attacker can still execute commands and read whatever new secrets the app can access.
06 · Verification

Crowdsourced verification payload.

Run this on the target RAGFlow host or inside the ragflow-server container. Example: docker exec -i ragflow-server bash -s -- /ragflow < ./check_cve_2026_28797.sh or, from a source checkout, bash ./check_cve_2026_28797.sh /path/to/ragflow; no root is required unless you need docker exec access.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_28797.sh
# Detects likely vulnerable vs patched RAGFlow code for CVE-2026-28797
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u

TARGET="${1:-/ragflow}"
if [ ! -d "$TARGET" ]; then
  if [ -d ".git" ] && [ -f "agent/component/string_transform.py" ]; then
    TARGET="."
  fi
fi

STR_FILE="$TARGET/agent/component/string_transform.py"
MSG_FILE="$TARGET/agent/component/message.py"

if [ ! -f "$STR_FILE" ] || [ ! -f "$MSG_FILE" ]; then
  echo "UNKNOWN - could not find RAGFlow source files under: $TARGET"
  exit 2
fi

has_vuln_pattern() {
  local f="$1"
  grep -Eq 'from jinja2 import Template as Jinja2Template|Jinja2Template\(' "$f"
}

has_patch_pattern() {
  local f="$1"
  grep -Eq 'from jinja2\.sandbox import SandboxedEnvironment|SandboxedEnvironment\(|_jinja2_sandbox|from_string\(' "$f"
}

str_vuln=0
msg_vuln=0
str_patch=0
msg_patch=0

has_vuln_pattern "$STR_FILE" && str_vuln=1
has_vuln_pattern "$MSG_FILE" && msg_vuln=1
has_patch_pattern "$STR_FILE" && str_patch=1
has_patch_pattern "$MSG_FILE" && msg_patch=1

version_hint="unknown"
if [ -f "$TARGET/README.md" ]; then
  version_hint=$(grep -Eo 'v0\.[0-9]+\.[0-9]+' "$TARGET/README.md" | head -n1 || true)
  [ -z "$version_hint" ] && version_hint="unknown"
fi

if [ "$str_vuln" -eq 1 ] || [ "$msg_vuln" -eq 1 ]; then
  echo "VULNERABLE - unsandboxed Jinja2 usage detected (version hint: $version_hint)"
  exit 1
fi

if [ "$str_patch" -eq 1 ] && [ "$msg_patch" -eq 1 ]; then
  echo "PATCHED - sandboxed Jinja2 patterns detected in both vulnerable components (version hint: $version_hint)"
  exit 0
fi

echo "UNKNOWN - source present but could not confidently classify patched state (version hint: $version_hint)"
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, inventory every RAGFlow instance at 0.24.0 or earlier, then immediately separate the internet-reachable ones from the internal-only ones because the presence of self-registration is the practical risk multiplier here. For this HIGH verdict, the noisgate mitigation SLA is within 30 days: disable public registration, gate the app behind SSO/VPN/IP allowlists, and restrict Agent workflow access; the noisgate remediation SLA is within 180 days: move all instances to v0.25.0 or later and verify the vulnerable components use SandboxedEnvironment rather than raw jinja2.Template.

Sources

  1. NVD entry
  2. GitHub Security Advisory GHSA-vvwj-fvwh-4whx
  3. RAGFlow releases
  4. RAGFlow v0.25.0 patched file evidence
  5. RAGFlow release notes
  6. CISA Known Exploited Vulnerabilities Catalog
  7. FIRST EPSS overview
  8. Shodan facet page showing indexed `RAGFlow` banners
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.