← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-41948 · CWE-23 · Disclosed 2026-05-18

Dify version 1

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

This is a hotel guest key that can be tricked into opening the staff hallway if you already got through the lobby

CVE-2026-41948 is a path traversal in Dify's proxying to the Plugin Daemon internal REST API. Affected builds are Dify 1.14.1 and earlier. The vulnerable flow forwards caller-controlled path material to the plugin daemon without adequately rejecting traversal segments, so an attacker can use crafted task identifiers or filename parameters to step outside the intended tenant-scoped path and hit internal endpoints such as debug surfaces.

The vendor/NVD-style 9.4 CRITICAL rating is too hot for most enterprise patch queues. The real-world chain requires an attacker to first become an authenticated Dify user, then know or discover a victim tenant UUID, then hit the specific proxyable path in a way that survives normalization. That is still bad in shared Dify environments because it breaks tenant isolation, but it is not equivalent to anonymous one-packet internet compromise. The one major amplifier is that Dify Cloud allows free self-registration, which weakens the usual value of the auth prerequisite.

"Serious tenant-isolation break, but not internet-wide pre-auth RCE. Treat it as high-priority auth-required abuse."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Get a Dify account

The attacker needs a valid Dify user context before they can drive the vulnerable proxy path. On Dify Cloud this can be as simple as self-registering an account; on enterprise self-hosted deployments it usually means SSO, local invitation, or prior compromise. Tooling here is trivial: a browser session or scripted HTTP client such as curl.
Conditions required:
  • Dify instance is reachable to the attacker
  • Attacker can self-register or otherwise obtain a valid user session
Where this breaks in practice:
  • Many self-hosted enterprise deployments sit behind SSO, VPN, or private ingress
  • If invite-only signup is enforced, the bug becomes post-auth instead of internet-sprayable
Detection/coverage: Little value from unauthenticated perimeter scanning alone. Identity logs are better: watch for newly created users immediately probing plugin- or file-related APIs.
STEP 02

Identify a victim tenant UUID

Per the advisory, successful abuse requires knowledge of the victim tenant UUID. An attacker can collect this from exposed links, shared artifacts, predictable application behavior, or by enumerating API responses from their own account using Burp Repeater or curl. This is where GitHub's AC:H view makes more practical sense than the flat AC:L baseline.
Conditions required:
  • Attacker has a valid session
  • Attacker can learn or infer a target tenant UUID
Where this breaks in practice:
  • UUID discovery is a real prerequisite and may require tenant-specific recon
  • Well-isolated tenants and minimal metadata leakage slow this step
Detection/coverage: Look for one account touching multiple tenant identifiers or unusual UUID-like references outside its normal workspace.
STEP 03

Abuse the plugin-daemon forwarder

The vulnerable code path described in PR #35796 joins a caller-supplied path onto the plugin daemon's inner API URL without rejecting traversal segments first. Using Burp Repeater, curl, or a custom script, the attacker supplies .. or encoded dot-segments in task identifiers or filename parameters so the forwarded request escapes the expected tenant-scoped namespace.
Conditions required:
  • The target is running Dify <= 1.14.1 or lacks the guard from PR #35796
  • The relevant plugin/file proxy route is exposed to the attacker's user role
Where this breaks in practice:
  • Traversal must survive decoding and routing quirks
  • Modern reverse proxies or custom request filters may already reject obvious .. sequences
Detection/coverage: Good web logs should show .., %2e%2e, or other suspicious path-segment anomalies in plugin/file routes. Scanner coverage is likely uneven because the advisory still lists patched versions as unknown.
STEP 04

Reach internal daemon endpoints and cross tenant boundaries

Once the path breakout works, the attacker can hit internal plugin-daemon endpoints that were supposed to remain behind tenant scoping, including debug-oriented surfaces noted in the advisories. The practical impact is unauthorized cross-tenant access to data or privileged internal functions, with confidentiality and integrity risk concentrated inside the Dify deployment rather than broad host takeover.
Conditions required:
  • Traversal request is accepted and forwarded
  • The internal endpoint reached exposes useful data or control surfaces
Where this breaks in practice:
  • Impact depends on what internal endpoints are reachable from the forwarded namespace
  • This is a tenant-isolation failure, not a demonstrated root-on-host exploit
Detection/coverage: Correlate app logs with plugin-daemon logs; internal/debug endpoints reached from tenant-facing routes are the giveaway.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo public exploitation evidence found in reviewed sources. I found no CISA KEV entry and no campaign reporting tied to this CVE.
Proof-of-concept availabilityNo reliable public weaponized PoC found. Huntr is referenced by NVD/VulnCheck, but the publicly retrievable details were limited; PR #35796 exposes the fix logic and enough detail for a competent operator to recreate the attack.
EPSS0.079% (23rd percentile) on the GitHub advisory page, sourced from FIRST. That is very low and argues against mass attacker interest right now.
KEV statusNot KEV-listed in the CISA KEV catalog as reviewed.
CVSS disagreementImportant split: NVD/CVE metadata shows 9.4 / AV:N/AC:L/PR:N/UI:N, while the GitHub advisory scores CVSS v4 at 9.2 with AC:H. The GitHub view better matches the real exploit chain because target-specific UUID knowledge and path-shaping are not zero-friction.
Affected versionsDify <= 1.14.1 according to NVD, VulnCheck, and GitHub advisory references.
Fixed versionPublicly ambiguous. PR #35796 merged on 2026-05-25, but the latest public release page in reviewed sources was v1.14.2 on 2026-05-19, and the GitHub advisory still says patched versions: unknown. Verify code presence, not just tag names.
Exposure shapeDify docs show the plugin daemon defaults to http://plugin_daemon:5002, i.e. an internal service-to-service path, which limits direct internet reach. However, Dify also documents optional remote debugging on port 5003 and exposed host mappings, so misconfigured self-hosted installs can widen exposure.
Disclosure and creditsDisclosed 2026-05-18. VulnCheck credits Ido Shani and Gal Zaban of Zafran Security.
Population / prevalenceDify is not niche hobbyware: the GitHub repo shows ~143k stars in reviewed sources. That raises operational importance, even though I found no authoritative Shodan/Censys count specific to this flaw.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to HIGH (8.1/10)

The decisive downward pressure is that exploitation is not meaningfully pre-auth in most enterprise deployments: the attacker needs a valid Dify user context and target-specific tenant knowledge before the traversal matters. It stays HIGH because the bug breaks tenant isolation and can expose internal plugin-daemon functionality in a platform that is often used as a shared service.

HIGH affected-version and root-cause characterization
MEDIUM practical exploitability and fixed-version mapping

Why this verdict

  • Auth requirement is real downward pressure — in self-hosted enterprises this usually implies prior access, SSO enrollment, or invitation. Vendor PR:N is technically defensible for Dify Cloud self-registration, but it overstates exposure for private deployments.
  • Target-knowledge raises friction — the attacker needs the victim tenant UUID and a path that breaks out of the intended namespace. GitHub's advisory modeling this as AC:H matches field reality better than a flat low-complexity assumption.
  • Impact is still serious once it lands — this is not cosmetic traversal. It can cross tenant boundaries into internal plugin-daemon/debug surfaces, which makes the blast radius meaningful inside shared Dify estates.

Why not higher?

I did not find KEV listing, public campaign reporting, or a broadly circulating turnkey exploit. More importantly, this is not demonstrated host-level RCE and it usually requires either self-registration or pre-existing user access plus target-specific recon, which keeps it below the 'drop everything' bucket.

Why not lower?

Free self-registration on Dify Cloud weakens the protection normally provided by authentication, so calling this merely medium would understate cloud/SaaS risk. And if you run Dify as a shared internal platform, tenant-boundary failures are exactly the sort of bug that turns one low-privilege foothold into cross-workspace data exposure.

05 · Compensating Control

What to do — in priority order.

  1. Disable open signup and tighten identity gates — If your deployment permits self-registration, stop treating this as a harmless auth-required bug. Move Dify behind SSO, invitation-only access, or VPN where possible; for a HIGH verdict, deploy this control within 30 days.
  2. Block traversal patterns at the reverse proxy — Reject requests containing .., %2e%2e, mixed-encoding dot segments, and suspicious filename/task identifier patterns on Dify API routes that touch plugin or file proxying. This is not a perfect fix, but it meaningfully cuts exploit reliability; deploy within 30 days.
  3. Keep plugin-daemon and debug ports private — Dify docs show internal daemon traffic on 5002 and optional debugging on 5003. Ensure those ports are not internet-exposed and are reachable only from the app tier or explicit admin workflows; validate within 30 days.
  4. Hunt for tenant-crossing path probes — Search ingress, app, and plugin-daemon logs for dot-segment traversal markers and for one account referencing multiple tenant UUIDs. This is your best immediate signal of attempted exploitation; turn on monitoring within 30 days.
What doesn't work
  • Relying on the plugin daemon's shared secret alone doesn't solve this, because the vulnerable path is forwarded by the trusted Dify application on the attacker's behalf.
  • Patching or removing individual plugins is not the fix; the flaw is in the proxying path handling before plugin-daemon requests are made.
  • A generic perimeter WAF with no application-specific path normalization rules may miss encoded or route-specific traversal variants.
06 · Verification

Crowdsourced verification payload.

Run this on a self-hosted Dify app host or container filesystem where the Dify source tree is present. Invoke it as bash verify_cve_2026_41948.sh /path/to/dify (example: bash verify_cve_2026_41948.sh /app/dify). It needs read-only access to the Dify tree; no root is required unless your container filesystem permissions demand it.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# verify_cve_2026_41948.sh
# Exit codes:
#   0 = PATCHED
#   1 = VULNERABLE
#   2 = UNKNOWN

set -euo pipefail

ROOT="${1:-.}"
FILE="$ROOT/api/core/plugin/impl/base.py"

semver_lte() {
  # returns 0 if $1 <= $2
  local a b IFS=.
  read -r -a a <<< "${1#v}"
  read -r -a b <<< "${2#v}"
  for i in 0 1 2; do
    local ai="${a[$i]:-0}"
    local bi="${b[$i]:-0}"
    if (( ai < bi )); then return 0; fi
    if (( ai > bi )); then return 1; fi
  done
  return 0
}

if [[ ! -f "$FILE" ]]; then
  echo "UNKNOWN - expected file not found: $FILE"
  exit 2
fi

# The merged fix in PR #35796 adds a traversal guard in api/core/plugin/impl/base.py.
if grep -q "Invalid plugin daemon path: traversal sequence detected" "$FILE" \
   || grep -q "traversal sequence detected" "$FILE"; then
  echo "PATCHED - traversal guard string found in $FILE"
  exit 0
fi

if grep -q "unquote(path)" "$FILE" && grep -q "%2e%2e" "$FILE"; then
  echo "PATCHED - path decode and encoded-dot traversal checks found in $FILE"
  exit 0
fi

VERSION=""
if command -v git >/dev/null 2>&1 && [[ -d "$ROOT/.git" ]]; then
  VERSION="$(git -C "$ROOT" describe --tags --exact-match 2>/dev/null || true)"
fi

if [[ -n "$VERSION" ]]; then
  if semver_lte "$VERSION" "1.14.1"; then
    echo "VULNERABLE - version $VERSION and no traversal guard found"
    exit 1
  else
    echo "UNKNOWN - version $VERSION is newer than 1.14.1, but guard pattern was not found; validate whether the fix was backported differently"
    exit 2
  fi
fi

echo "UNKNOWN - no git tag found and no known fix pattern detected; compare api/core/plugin/impl/base.py against PR #35796"
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: identify every internet-facing or multi-tenant Dify deployment, confirm whether self-registration is enabled, and verify whether PR #35796's guard is present instead of trusting release labels. For this HIGH verdict, use the noisgate mitigation SLA to put compensating controls in place within 30 days and the noisgate remediation SLA to move to a vendor build that definitively contains the fix within 180 days; given the public fixed-version ambiguity, your remediation should include a code-level validation step before you close the ticket.

Sources

  1. NVD CVE-2026-41948
  2. GitHub Advisory Database - GHSA-h666-98mq-949j
  3. Dify PR #35796 fix details
  4. VulnCheck advisory
  5. Dify releases page
  6. Dify self-hosted environment variables
  7. Dify plugin remote debugging docs
  8. CISA Known Exploited Vulnerabilities Catalog
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.