Skip to content

Path Traversal Vulnerability in ShStaticFileAPI #1028

@intSheep

Description

@intSheep

Path Traversal Vulnerability in ShStaticFileAPI

Dear Shio Project Maintainers,

I hope this message finds you well. I am writing to report a security vulnerability that I have identified in the Shio Content Management System. This report is intended to help improve the security of your project and protect your users.

Summary

A path traversal vulnerability exists in the shStaticFilePreUpload method of ShStaticFileAPI.java in the Shio application. This vulnerability allows attackers to read arbitrary files on the server by manipulating the fileName parameter.

Affected System

  • System: Shio - Java-based Content Management System
  • Repository: https://github.com/openviglet/shio
  • Affected Versions: All versions prior to the current development version
  • Component: Static File API Module

Affected Component

  • File: shio-app/src/main/java/com/viglet/shio/api/staticfile/ShStaticFileAPI.java
  • Method: shStaticFilePreUpload
  • Line: 107-126

Vulnerability Details

Root Cause

The vulnerability stems from insufficient input validation of the fileName parameter. The application directly uses user-controlled input without proper path traversal detection or sanitization.

Technical Analysis

  1. Input Source: The fileName parameter is directly extracted from the URL path variable @PathVariable String fileName
  2. Insufficient Validation: No validation is performed to check for path traversal sequences
  3. Path Construction: The file path is constructed using shFolderUtils.dirPath() and shFolderUtils.filePath() methods
  4. Directory Traversal: Attackers can use ../ sequences to navigate outside the intended directory

Vulnerable Code

@GetMapping("/pre-upload/{folderId}/{fileName}")
@JsonView({ ShJsonView.ShJsonViewObject.class })
public ResponseEntity<ShHttpMessageBean> shStaticFilePreUpload(@PathVariable String fileName,
        @PathVariable String folderId) {

    ShFolder shFolder = shFolderRepository.findById(folderId).orElse(null);
    if (!shStaticFileUtils.fileExists(shFolder, fileName)) {
        // File existence check without path validation
    }
}

Attack Vector

An attacker can exploit this vulnerability by sending a request with a malicious fileName parameter containing path traversal sequences:

GET /api/v2/staticfile/pre-upload/{folderId}/../../../etc/passwd

Impact

  • Information Disclosure: Attackers can read sensitive system files
  • Security Bypass: Potential access to configuration files, logs, and other sensitive data
  • Privilege Escalation: May lead to further exploitation if sensitive information is obtained

Proof of Concept

  1. Identify a valid folderId in the system
  2. Send a GET request to /api/v2/staticfile/pre-upload/{folderId}/../../../etc/passwd
  3. The application will attempt to check if the file exists, potentially revealing file system information

Recommended Fix

Immediate Fix

Implement strict input validation for the fileName parameter:

@GetMapping("/pre-upload/{folderId}/{fileName}")
@JsonView({ ShJsonView.ShJsonViewObject.class })
public ResponseEntity<ShHttpMessageBean> shStaticFilePreUpload(@PathVariable String fileName,
        @PathVariable String folderId) {

    // Validate fileName for path traversal attempts
    if (fileName == null || fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
        return ResponseEntity.badRequest().build();
    }

    ShFolder shFolder = shFolderRepository.findById(folderId).orElse(null);
    if (!shStaticFileUtils.fileExists(shFolder, fileName)) {
        // ... existing code ...
    }
}

Comprehensive Fix

  1. Path Normalization: Use Path.normalize() to detect path traversal attempts
  2. Whitelist Validation: Implement strict filename validation using regex patterns
  3. Directory Validation: Ensure the final path remains within the intended directory
  4. Input Sanitization: Remove or escape dangerous characters
private boolean isValidFileName(String fileName) {
    if (fileName == null || fileName.isEmpty()) {
        return false;
    }
    
    // Check for path traversal sequences
    if (fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
        return false;
    }
    
    // Validate against allowed characters
    return fileName.matches("^[a-zA-Z0-9._-]+$");
}

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions