Back to skill

Security audit

ragflow-skill-python0418

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for RAGFlow management, but it can expose your API key and uploaded documents if pointed at a plain HTTP server.

Install only if you trust the configured RAGFlow server. Use an HTTPS RAGFLOW_API_URL, avoid sending sensitive documents over plain HTTP, and prefer a dedicated least-privilege API key. Confirm exact dataset or document IDs before any delete, because the underlying scripts can modify or remove remote RAGFlow data.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/common.py:85
Finding

Bearer Credentials and Uploaded Documents May Be Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/common.py:85-91, scripts/common.py:174-183, and scripts/upload.py:122-130
Vulnerability Type: Plaintext transmission of sensitive information
Risk Level: High

Vulnerable Code

scripts/common.py:85-91 permits any absolute URL with a scheme and network location, including plaintext HTTP:

python
def resolve_base_url(cli_base_url: str | None = None) -> str:
    base_url = (cli_base_url or "").strip() or _require_env_var(RAGFLOW_API_URL_ENV)

    parsed = urllib.parse.urlsplit(base_url)
    if not parsed.scheme or not parsed.netloc:
        raise ConfigError(
            f"Invalid {RAGFLOW_API_URL_ENV}. Use an absolute URL such as http://127.0.0.1:9380."
        )
    return base_url.rstrip("/")

scripts/common.py:174-183 sends the API key as a bearer credential to the accepted URL:

python
headers = {"Authorization": f"Bearer {api_key}"}
if accept:
    headers["Accept"] = accept
if content_type:
    headers["Content-Type"] = content_type

request_obj = urllib.request.Request(url, headers=headers, data=body, method=method)

try:
    with urllib.request.urlopen(request_obj, timeout=HTTP_TIMEOUT) as response:
        return decode_json_response(response.read())

scripts/upload.py:122-130 sends both the bearer credential and the complete multipart document body over the configured transport:

python
boundary, body = _build_multipart(file_paths)
url = f"{base_url}/api/v1/datasets/{dataset_id}/documents"
request_obj = urllib.request.Request(url, data=body, method="POST")
request_obj.add_header("Authorization", f"Bearer {api_key}")
request_obj.add_header("Content-Type", f"multipart/form-data; boundary={boundary}")

try:
    with urllib.request.urlopen(request_obj, timeout=120) as response:
        payload = decode_json_response(response.read())

Technical Analysis

The shared URL validation checks only that a scheme and network location exist. It does not require HTTPS, ...[truncated 2833 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require HTTPS by default

    • Accept only https for non-loopback endpoints.
    • Reject unknown schemes explicitly.
    • Do not silently downgrade or redirect sensitive requests from HTTPS to HTTP.
  2. Restrict development-time HTTP use

    • Permit HTTP only for verified loopback hosts such as 127.0.0.1, ::1, or localhost.
    • Require an explicit, clearly named opt-in flag for any broader plaintext use.
    • Emit a prominent security warning when plaintext transport is enabled.
  3. Correct configuration guidance

    • Replace the current HTTP example with an HTTPS example.
    • Document that the API key and uploaded files are transmitted to RAGFLOW_API_URL.
    • Explain the security implications of using HTTP.
  4. Harden TLS behavior

    • Retain standard certificate and hostname verification.
    • Support a configured private CA bundle for self-hosted deployments rather than recommending disabled verification.
    • Consider certificate pinning in environments with strict endpoint trust requirements.
  5. Limit credential impact

    • Use a dedicated, least-privilege RAGFlow API key for this Skill.
    • Separate read-only and mutation credentials where RAGFlow supports that model.
    • Rotate any key that may previously have been used over untrusted HTTP.
  6. Add regression tests

    • Verify that remote http:// URLs are rejected.
    • Verify that loopback HTTP is accepted only under the documented exception policy.
    • Verify that redirects cannot move authorization headers or uploaded bodies to an untrusted or plaintext destination.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The supplied code is specifically a datasets CLI script. Its subcommands are list, info, create, and delete, all against /api/v1/datasets. That is consistent with part of the declared description, but the declaration describes a broader multi-function skill for many RAGFlow dataset-related tasks, including document management, parsing operations, search/chunk retrieval, model listing, and dataset update. None of those additional capabilities appear in this code chunk. Because the declared description materially overstates what this code actually does, the description does not accurately represent this code chunk on its own.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 43)May include surrounding context.

md
python3 scripts/upload.py DATASET_ID /path/to/file.pdf --json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 44)May include surrounding context.

md
python3 scripts/upload.py DATASET_ID /path/to/file.pdf --json

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · SKILL.md (reported line 69)May include surrounding context.

md
- If a parse status result includes `progress_msg`, surface it directly. For `FAIL`, treat it as the primary error detail.
- Use `--retrieval-test` only for single-dataset debugging or when the user explicitly asks for that endpoint.

## Output Rules

- Follow `reference.md`.
- Use tables for 3+ items when possible.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares access to sensitive capabilities through required environment variables and implied network/file usage, but it does not define any explicit tool scope such as permissions or allowed-tools. That increases the blast radius if the skill is invoked in a broader execution context, because an agent may be able to use more tools or resources than the skill contract makes clear.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The delete command performs an irreversible destructive API call as soon as --ids is provided, with no confirmation prompt, dry-run mode, or explicit force flag. In an agent skill context, this is more dangerous because an LLM or automation layer can invoke deletion from ambiguous instructions, causing accidental data loss across one or multiple datasets.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The delete_documents function issues a DELETE request that removes documents from the dataset, which is a destructive operation. The code provides no confirmation prompt and no inline comment or docstring warning that this action is irreversible or deletes remote data.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/common.py (reported line 59)May include surrounding context.

python
return

    for stream_name in ("stdout", "stderr"):
        stream = getattr(sys, stream_name, None)
        if stream is None or not hasattr(stream, "reconfigure"):
            continue
        try:

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The top-level argparse description says the script is for "List, inspect, or create RAGFlow datasets," which implies non-destructive operations plus creation only. However, the code defines and executes a delete subcommand that performs dataset deletion via HTTP DELETE.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code file performs a network-backed status retrieval and then prints potentially sensitive dataset metadata, including document identifiers and progress or error messages, directly to the console. There is no user-facing disclosure in the script output, prompt, or inline warning that running the command will expose this information locally or in logs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This Python file sends the user-provided query and optional document/dataset identifiers to a remote retrieval API at L194-L201, then prints retrieved content previews at L250-L260. The file has no confirmation prompt, warning comment, docstring, or user-facing disclosure in the code explaining that input data is sent over the network and matching content will be echoed to output.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code performs a PUT request to update a remote document using payload data assembled from user-provided JSON and flags. While the script name suggests updating documents is its purpose, there is no visible prompt, warning, or disclosure in the code that local file-sourced JSON passed via @path will be transmitted to the remote API.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.