CVE-2025-66292

DPanel's Delete Function Works Too Well: A Tale of Path Traversal

Alon Barad
Alon Barad
Software Engineer

Jan 15, 2026·6 min read

Executive Summary (TL;DR)

DPanel v1.9.1 and older contains a critical flaw in its attachment deletion logic. The application blindly trusts user-supplied paths, allowing an authenticated attacker to break out of the intended storage directory and delete any file the process has access to. A fix was released in v1.9.2 using Go's `filepath.IsLocal` check.

An arbitrary file deletion vulnerability in DPanel allows authenticated users to nuke system files via directory traversal sequences.

The Hook: When "Delete" Means "Destroy"

Server management panels are the Swiss Army knives of the infrastructure world. They promise to make complex tasks simple: spin up a database, manage cron jobs, or handle file uploads with a click. But as any security researcher knows, the more abstraction you layer over a system, the more places there are to hide a catastrophic logic error. DPanel, a popular Go-based open-source panel, recently fell victim to this exact paradox.

The vulnerability, tracked as CVE-2025-66292, resides in a seemingly innocuous feature: deleting attachments. It’s the kind of feature developers implement on autopilot. You upload a file; you delete a file. Simple. Boring, even. But in the world of vulnerability research, "boring" is where the bugs live. The developers assumed that when a user asks to delete image.png, they actually mean image.png.

They didn't count on us asking to delete ../../../../etc/passwd. In versions prior to 1.9.2, DPanel doesn't just delete the attachment; it dutifully resolves the path traversal sequences and deletes whatever file lies at the end of the rainbow. It’s not just a file deletion bug; it’s a "delete anything the web server can touch" bug. This isn't just dropping a table; it's potentially bricking the operating system.

The Flaw: Trusting the Path

The root cause here is a classic failure to sanitize input boundaries, specifically involving path traversal (CWE-22). In Go, managing file paths can be deceptive. The standard library provides excellent tools like filepath.Join and filepath.Clean, which are designed to normalize paths. However, normalization is not the same as sanitization. Normalizing ../../etc/passwd correctly resolves it to /etc/passwd (assuming a root context), which is syntactically correct but semantically disastrous for a web application.

The logic flaw occurred in the hand-off between the HTTP controller and the storage service. The controller accepted a raw path string from a JSON payload. Instead of verifying that this path pointed to a file inside the allowed upload directory, the application simply passed it to a helper function that constructed an absolute path. The application operated on the assumption that the user input was a filename, not a relative path command.

This is akin to a hotel concierge who, when asked to clean room 101, cleans room 101. But when asked to clean "the room three floors down and two doors to the left," they dutifully march downstairs and start scrubbing the bank vault next door. The application lacked a "jail" check—a verification step to ensure the final resolved path still starts with the expected base directory prefix.

The Code: The Smoking Gun

Let's look at the crime scene. The vulnerable function is Delete in app/common/http/controller/attach.go. Here is the logic before the patch:

// Vulnerable Code
func (self Attach) Delete(http *gin.Context) {
    // ... validation ...
    // 1. User input 'params.Path' is passed directly to the storage helper
    path := storage.Local{}.GetSaveRealPath(params.Path)
    
    // 2. We check if the file exists
    _, err := os.Stat(path)
    if err == nil {
        // 3. EXECUTION: The file is deleted. No questions asked.
        os.Remove(path)
    }
    self.JsonSuccessResponse(http)
    return
}

The GetSaveRealPath function likely joins a base path with the input. If params.Path is ../../etc/hosts, os.Remove receives the resolved system path. There are no guardrails.

The fix, implemented in commit cbda0d90204e8212f2010774345c952e42069119, leverages a newer Go feature (introduced in Go 1.20) called filepath.IsLocal. This function is a game-changer for preventing traversal attacks because it explicitly checks if a path is lexical, relative, and does not ascend above the current directory.

// Patched Code
if !self.Validate(http, &params) {
    return
}
 
// THE FIX: Reject paths that try to escape
if !filepath.IsLocal(params.Path) {
    self.JsonResponseWithError(http, 
        function.ErrorMessage(define.ErrorMessageCommonDataNotFoundOrDeleted), 
        500
    )
    return
}
 
params.Path = filepath.Clean(params.Path)
path := storage.Local{}.GetSaveRealPath(params.Path)
// ... proceed to delete ...

By adding filepath.IsLocal, the developer ensures that any input containing .. sequences that would break out of the directory is rejected immediately.

The Exploit: Nuke It From Orbit

Exploiting this requires low-level privileges (PR:L), specifically access to the backend API. However, in many organizations, "admin" panels are shared, or credentials are hardcoded/leaked. Once authenticated, the attack is trivial. We don't need fancy shellcode; we just need a valid JWT and a JSON payload.

Here is how an attacker would manually verify and exploit this. First, they identify the target endpoint /api/common/attach/delete. Then, they craft a request to delete a non-essential but verifiable system file to confirm the vulnerability (e.g., a temp file), before moving on to high-value targets.

The Attack Payload:

POST /api/common/attach/delete HTTP/1.1
Host: target-dpanel.local
Authorization: Bearer <Your-JWT-Here>
Content-Type: application/json
 
{
  "path": "../../../../../../etc/mysql/my.cnf"
}

When the server processes this, it resolves the path relative to the attachment storage root. If the storage root is /opt/dpanel/storage/uploads, the payload resolves to /etc/mysql/my.cnf. The os.Remove call triggers, and suddenly the database configuration is gone. When the service restarts, the database fails. DoS achieved.

An attacker could get more creative: deleting dpanel.toml (the application's own config), deleting SSH authorized keys to lock out admins, or deleting log files to cover tracks from previous intrusions.

The Impact: Silence is Deadly

While this vulnerability scores an 8.1 (High) rather than a 9.8 (Critical), do not underestimate it. The lack of Confidentiality impact (you can't read the files, only delete them) keeps the score down, but the Integrity and Availability impacts are total.

From an availability standpoint, this is a nuclear option. An attacker can systematically delete the binaries required to run the OS, effectively requiring a full server reinstall. In a cloud environment, this might mean downtime for critical business logic managed by the panel.

Furthermore, consider the security implications of deleting specific files. If an attacker deletes .htaccess or other access control definition files, they might inadvertently (or purposefully) open up other parts of the system to unauthenticated access. They could delete lock files to trigger race conditions. In the worst-case scenario, if the application runs as root (which, sadly, many of these panels do), the attacker can render the entire operating system unbootable.

The Fix: Containment Strategy

The immediate remediation is to upgrade DPanel to version v1.9.2. The patch provided by donknap is robust because it uses the standard library's filepath.IsLocal, which avoids the pitfalls of writing custom regex or string parsing logic to detect .. sequences.

For developers reading this: this is a lesson in defensive programming. Never trust file system operations with raw user input. If you must accept a filename, verify it against an allowlist of characters (e.g., alphanumeric only) or use strict lexical checks like IsLocal.

Additionally, this highlights the importance of Principle of Least Privilege. Why does a web panel need write access to /etc/ or /bin/? It shouldn't. Running the DPanel service as a dedicated, low-privileged user would mitigate the impact of this vulnerability significantly. Even if the code is flawed, the OS permissions would prevent the deletion of critical system files.

Fix Analysis (1)

Technical Appendix

CVSS Score
8.1/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H

Affected Systems

DPanel Server Management Panel

Affected Versions Detail

Product
Affected Versions
Fixed Version
DPanel
donknap
< 1.9.21.9.2
AttributeDetail
CWE IDCWE-22 (Path Traversal)
Attack VectorNetwork
CVSS v3.18.1 (High)
Privileges RequiredLow (Authenticated)
ImpactHigh Integrity, High Availability
Exploit StatusPOC Available
CWE-22
Path Traversal

The application allows user input to control a file path used in a deletion operation without properly validating that the path is within the intended directory.

Vulnerability Timeline

Vulnerability fixed in commit cbda0d
2025-12-01
GHSA-vh2x-fw87-4fxq published
2026-01-15
CVE-2025-66292 Assigned
2026-01-15

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.