RAGFlow's retrieval pipeline calls eval() on the tag_feas field stored in document chunks (rag/nlp/search.py, _rank_feature_scores(), line ~287). The tag_feas field is intended to hold a dict of tag-name-to-score mappings (e.g. {"security": 0.85}) used for rank feature scoring during retrieval. However, the value is accepted via the chunk creation API with no validation and stored as a plain string. When retrieval triggers the tag-reranking code path, eval() executes the stored string — allowing any authenticated user to achieve remote code execution as the RAGFlow process (typically root in Docker).
This POC demonstrates the vulnerability by obtaining an interactive reverse shell inside the RAGFlow container.
Severity: Critical
CWE: CWE-95 (Improper Neutralization of Directives in Dynamically Evaluated Code)
Affected: RAGFlow with Infinity as DOC_ENGINE (Elasticsearch is not affected — its rank_features field type enforces numeric values at the storage layer)
If you already have a RAGFlow instance running with Infinity as the DOC_ENGINE, you can skip this section and go straight to Running the POC.
The setup/ directory contains a Docker Compose environment that stands up RAGFlow with all the necessary configuration. It includes:
- RAGFlow v0.24.0 with
DOC_ENGINE=infinity - Infinity v0.7.0-dev5 (vector/fulltext database)
- TEI embedding model (bge-small-en-v1.5)
- TEI reranker model (ms-marco-TinyBERT-L-2-v2)
- MySQL, MinIO, Redis (supporting services)
Requirements: Docker and Docker Compose.
cd setup
./setup.shThis pulls images, starts all services, waits for health checks, and registers a test user. It takes a few minutes on first run (model downloads).
When setup completes, it prints connection details. The test user credentials are:
- URL: http://localhost:18080
- Email:
poc@test.local - Password:
ragflow123
To tear everything down (stops containers, removes volumes):
./teardown.shThe POC requires a RAGFlow API key. If you're using the test environment from above:
- Log in at http://localhost:18080 as
poc@test.local/ragflow123 - Go to Settings > Model Providers > API tokens
- Click Create new API token and copy the key
Then run:
pip install requests # only dependency
python3 poc/poc.py \
--base-url http://localhost:18080 \
--api-key <your-api-key> \
--embedding-base http://tei:80/v1 \
--reranker-base tei-reranker:80 \
--infinity-url http://localhost:23820The --embedding-base, --reranker-base, and --infinity-url flags are only needed for the test setup. On a production instance with models already configured, only --base-url and --api-key are required.
See the docstring at the top of poc/poc.py for full details on preconditions, what each step does, and all available options.