# File Operations Security Detection Module

> Security detection for file download, upload, path traversal, and other operations
> Security rules based on RuoYi system audit experience

## File Download Security Detection (with Scheduled Task Cases)

### Risk Pattern 1: Indirect File Write via Scheduled Tasks (High Risk)

#### Vulnerable Code Example
```java
// High Risk: Indirectly writing files via scheduled tasks
@PostMapping("/monitor/job/add")
public AjaxResult addSave(SysJob job) {
    // Attacker can create scheduled tasks to execute arbitrary file operations
    // invokeTarget: "ruoYiConfig.setProfile('/etc/passwd')"
    return toAjax(jobService.insertJobCron(job));
}

// Actual execution
public class ScheduleRunnable implements Runnable {
    public void run() {
        method.invoke(target, params);  // Arbitrary file write
    }
}
```

#### Attack Vector
```json
{
    "jobName": "ruoYiConfig.setProfile",
    "invokeTarget": "ruoYiConfig.setProfile('C://windows/win.ini')",
    "jobGroup": "DEFAULT",
    "cronExpression": "0/10 * * * * ?",
    "status": "1"
}
```

### Detection Commands
```bash
# Scheduled task file operation detection
grep -rn "@.*Mapping.*/monitor/job" --include="*.java" -A 10 | grep -E "invokeTarget|methodName|methodParams"

# Reflection-based file operation detection
grep -rn "method\.invoke" --include="*.java" -B 10 -A 5 | grep -E "setProfile|writeFile|save"

# Spring Bean file operation detection
grep -rn "SpringContextUtil\.getBean" --include="*.java" -B 5 -A 5 | grep -E "Config|File|Profile"
```

## Minimal PoC Examples
```bash
# Path traversal download
curl "https://app.example.com/common/download?fileName=../../../../etc/passwd"

# Upload type bypass (only size validation)
curl -F "file=@/etc/passwd;type=text/plain" https://app.example.com/upload

# Scheduled task file write/execution
curl -X POST https://app.example.com/monitor/job/add \
  -H "Content-Type: application/json" \
  -d '{"jobName":"pwn","invokeTarget":"ruoYiConfig.setProfile('/"'"'"/etc/passwd'"'"'/)","cronExpression":"0/1 * * * * ?"}'
```

## File Download Security Detection

### Risk Pattern 1: Path Traversal Download Vulnerability (Based on RuoYi Case)

#### Vulnerable Code Example
```java
// High Risk: Path traversal vulnerability in CommonController
@RequestMapping("common/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response) {
    String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
    String filePath = Global.getDownloadPath() + fileName;  // Direct path concatenation

    response.setHeader("Content-Disposition", "attachment;fileName=" + setFileDownloadHeader(request, realFileName));
    FileUtils.writeBytes(filePath, response.getOutputStream());  // Arbitrary file read
}

// Attack vector
GET /common/download?fileName=../../../etc/passwd
GET /common/download?fileName=/Windows/system.ini
```

#### Detection Regex
```bash
# 1. File download interface detection
grep -rn "@.*Mapping.*download" --include="*.java"

# 2. Path concatenation pattern detection
grep -rn "get.*Path\(\)\s*\+\s*" --include="*.java"

# 3. File operation detection
grep -rn "FileUtils\.writeBytes\|getOutputStream" --include="*.java"

# 4. Response header setting detection
grep -rn "setHeader.*fileName" --include="*.java"
```

### Risk Pattern 2: Response Header Injection Vulnerability

#### Vulnerable Code Example
```java
// Medium Risk: Response header injection risk
public String setFileDownloadHeader(HttpServletRequest request, String fileName) {
    final String agent = request.getHeader("USER-AGENT");
    String filename = fileName;  // User-controlled filename

    if (agent.contains("MSIE")) {
        filename = URLEncoder.encode(filename, "utf-8");
    }
    // ... other browser handling

    return filename;  // Possible CRLF injection
}

// Attack vector
GET /common/download?fileName=test.txt%0D%0AHeader-Injection: value
```

---

## Security Fix Solutions (Based on RuoYi Vulnerabilities)

### Fix 1: Path Normalization and Validation

```java
// Secure: Path-normalized download interface (RuoYi fixed version)
@RequestMapping("common/download")
public void fileDownloadSafe(String fileName, Boolean delete, HttpServletResponse response) {
    // 1. Path normalization
    Path basePath = Paths.get(Global.getDownloadPath()).normalize();
    Path filePath = basePath.resolve(fileName).normalize();

    // 2. Security check
    if (!filePath.startsWith(basePath)) {
        throw new SecurityException("Invalid file path");
    }

    // 3. File type whitelist
    if (!isAllowedFileType(filePath)) {
        throw new SecurityException("File type not allowed");
    }

    // 4. File existence check
    if (!Files.exists(filePath) || !Files.isRegularFile(filePath)) {
        throw new FileNotFoundException("File not found");
    }

    FileUtils.writeBytes(filePath.toString(), response.getOutputStream());
}

private boolean isAllowedFileType(Path filePath) {
    String extension = getFileExtension(filePath.toString());
    return Arrays.asList("pdf", "txt", "jpg", "png").contains(extension);
}
```

### Fix 2: Secure Filename Handling

```java
// Secure: Safe response header handling (RuoYi fixed version)
public String setFileDownloadHeaderSafe(HttpServletRequest request, String fileName) {
    // 1. Filename sanitization
    String safeFileName = sanitizeFileName(fileName);

    // 2. Encoding handling
    final String agent = request.getHeader("USER-AGENT");
    String encodedName;

    if (agent.contains("MSIE") || agent.contains("Trident")) {
        encodedName = URLEncoder.encode(safeFileName, "UTF-8")
                .replace("+", "%20");
    } else if (agent.contains("Firefox")) {
        encodedName = "=?UTF-8?B?" +
                Base64.getEncoder().encodeToString(safeFileName.getBytes(StandardCharsets.UTF_8)) + "?=";
    } else {
        encodedName = URLEncoder.encode(safeFileName, "UTF-8");
    }

    return encodedName;
}

private String sanitizeFileName(String fileName) {
    // Remove path traversal characters
    String sanitized = fileName.replaceAll("[/\\\\:]*\.\.[/\\\\:]*", "");
    // Remove control characters
    sanitized = sanitized.replaceAll("[\\x00-\\x1F\\x7F]", "");
    return sanitized;
}
```

### Missing Permission Control (Medium Risk)

#### Risk Pattern
```java
// Medium Risk: Missing permission control
@GetMapping("/download/{file}")
public void downloadFile(@PathVariable String file) {
    // Any logged-in user can access
}

// Medium Risk: Insufficient permission control
@RequiresPermissions("user:view")  // Permission too broad
@GetMapping("/download/{file}")
public void downloadFile(@PathVariable String file) {
    // ...
}
```

#### Secure Implementation
```java
// Secure: Fine-grained permission control
@RequiresPermissions("file:download")  // Specific permission
@GetMapping("/download/{file}")
public void downloadFile(@PathVariable String file) {
    // Business logic permission verification
    if (!hasFileAccessPermission(file)) {
        throw new SecurityException("No file access permission");
    }
    // ...
}
```

### File Upload Risks (High Risk)

#### Risk Pattern
```java
// High Risk: Insufficient type validation
@PostMapping("/upload")
public String upload(MultipartFile file) {
    // Only checks extension, can be bypassed
    if (!file.getOriginalFilename().endsWith(".jpg")) {
        return "Invalid file type";
    }
    // ...
}

// High Risk: Unsafe storage path
String filename = file.getOriginalFilename();
String path = "/uploads/" + filename;  // Path traversal risk
file.transferTo(new File(path));
```

---

## Detection Rules

### One-Click Detection Commands

```bash
# 1. File download interface detection
grep -rn "@GetMapping.*download\|@PostMapping.*download" --include="*.java"

# 2. File upload interface detection
grep -rn "@PostMapping.*upload\|MultipartFile" --include="*.java"

# 3. Path concatenation risk detection
grep -rn "path.*\\+.*fileName\|getPath().*\\+\|new File(.*\\.\\." --include="*.java"

# 4. Permission control check
grep -rn "@RequiresPermissions" --include="*.java" -A 2 | grep -E "download|upload|file"

# 5. File operation sink detection
grep -rn "new File(.*)\\|FileInputStream\|FileOutputStream\|Paths.get" --include="*.java"
```

### Framework-Specific Detection

#### Spring Boot Detection
```bash
# Spring MVC file operation interfaces
grep -rn "@GetMapping.*file\|@PostMapping.*file" --include="*.java"

# Path parameter binding risk
grep -rn "@PathVariable.*String.*file" --include="*.java"

# RequestParam file parameter
grep -rn "@RequestParam.*file" --include="*.java"
```

---

## Audit Checklist

### High-Risk Items (Critical)
- [ ] File download path traversal protection
- [ ] File upload type and content validation
- [ ] Path concatenation operation security
- [ ] File storage path security

### Medium-Risk Items (High)
- [ ] File operation permission control completeness
- [ ] Filename input validation and escaping
- [ ] File access logging
- [ ] File size and quantity limits

### Configuration Items (Medium)
- [ ] File storage directory permission configuration
- [ ] Temporary file cleanup mechanism
- [ ] File access rate limiting
- [ ] Sensitive file access control

---

## Fix Recommendations

### Path Traversal Protection
```java
// Enhanced path security check
public static boolean isSafeFilePath(String fileName, String basePath) {
    // Basic character check
    if (fileName == null || fileName.contains("..") ||
        fileName.contains("/") || fileName.contains("\\")) {
        return false;
    }

    // Path normalization verification
    Path normalizedBase = Paths.get(basePath).normalize();
    Path normalizedFile = Paths.get(basePath, fileName).normalize();

    return normalizedFile.startsWith(normalizedBase);
}
```

### File Upload Security
```java
// Secure file upload handling
@PostMapping("/upload")
@RequiresPermissions("file:upload")
public AjaxResult uploadFile(@Validated MultipartFile file) {
    // 1. File type validation
    if (!isAllowedFileType(file)) {
        return error("File type not allowed");
    }

    // 2. File size limit
    if (file.getSize() > MAX_FILE_SIZE) {
        return error("File size exceeds limit");
    }

    // 3. Safe filename generation
    String safeFileName = generateSafeFileName(file.getOriginalFilename());
    String filePath = getUploadPath() + safeFileName;

    // 4. Safe storage
    file.transferTo(new File(filePath));

    return success("Upload successful");
}
```

---

## Lessons Learned and Rule Updates

### Key Lessons from the RuoYi Audit (Systematic Blind Spot Analysis)

#### Blind Spot 1: Missing Path Concatenation Detection Rules
**Problem**: Traditional detection completely ignores common patterns like `basePath + fileName`
**Example**: `Global.getDownloadPath() + fileName` → Path traversal vulnerability
**Root Cause**: Detection rules lack the ability to recognize path concatenation patterns

#### Blind Spot 2: Insufficient Understanding of Framework Feature Security Risks
**Problem**: Security risks of Spring MVC auto parameter binding not considered
**Example**: `fileDownload(String fileName, ...)` auto-binds user input
**Root Cause**: Insufficient understanding of framework internals

#### Blind Spot 3: Missing Combined Attack Detection Capability
**Problem**: Detects individual vulnerabilities in isolation, ignoring path traversal + file download combinations
**Example**: Path traversal can lead to arbitrary file download
**Root Cause**: Detection lacks correlation and context awareness

#### Blind Spot 4: Insufficient Business Logic Deep Analysis
**Problem**: Only focuses on technical vulnerabilities, ignoring business logic security
**Example**: Business permission control for file download interfaces
**Root Cause**: Lack of analytical capability for complex business workflows

### Updated Detection Capabilities

#### New Detection Rule Groups
1. **Path Concatenation Detection**: `basePath + userInput` → File operations
2. **Framework Feature Detection**: Spring MVC parameter binding risks
3. **Combined Attack Detection**: Path traversal + file download combination
4. **Business Logic Detection**: File operation permission control

#### Enhanced Detection Methods
- **Data Flow Tracing**: Complete path from user input to file operations
- **Context Awareness**: Analysis combining framework features and business scenarios
- **Correlation Analysis**: Identify exploitation relationships between related vulnerabilities

### Continuous Improvement Directions
1. **Framework Knowledge Base**: Deep understanding of security features in mainstream frameworks
2. **Pattern Recognition Engine**: Build smarter vulnerability pattern recognition
3. **Automated Verification**: Develop automated tools for vulnerability verification
4. **Continuous Learning**: Keep up with new attack techniques and defense methods

Through this update, file operation security detection capabilities have been significantly improved, enabling more comprehensive discovery of file operation security risks in Java web applications.

## Fix Examples
- Path traversal: Use `Paths.get(base, userInput).normalize()` then check `startsWith(base)`
- Upload: Dual MIME + magic byte validation, write to random filename + isolated directory, prohibit overwriting
- Download: Whitelist paths/files, prohibit concatenating user input, add authentication/audit
- Scheduled tasks: Whitelist callable methods, prohibit reflection-based invocation of arbitrary bean methods

---

## File Deletion Security Detection (v2.5.0 New - Based on litemall Audit Experience)

> **Audit Blind Spot Warning**: File deletion functionality is often overlooked! Most audits only focus on upload and download, ignoring delete operations.
> This vulnerability was missed during the litemall project audit and was only discovered through CVE research (GitHub #564).

### Risk Pattern: Arbitrary File Deletion

#### Vulnerable Code Example (Java)
```java
// High Risk: Directly using user input to delete files
@PostMapping("/storage/delete")
public Object delete(@RequestBody String key) {
    storageService.delete(key);  // No path validation
    return ResponseEntity.ok();
}

// Storage service implementation
public void delete(String filename) {
    Path file = rootLocation.resolve(filename);  // Direct concatenation
    Files.delete(file);  // Arbitrary file deletion
}

// Attack vector
POST /admin/storage/delete
{"key": "../../../etc/important.conf"}
```

#### Vulnerable Code Example (Python)
```python
# High Risk: Path traversal deletion
@app.route('/delete', methods=['POST'])
def delete_file():
    filename = request.json.get('filename')
    filepath = os.path.join(UPLOAD_DIR, filename)  # Direct concatenation
    os.remove(filepath)  # Arbitrary file deletion
    return jsonify({'success': True})
```

#### Vulnerable Code Example (Go)
```go
// High Risk: Deletion without path validation
func DeleteFile(c *gin.Context) {
    filename := c.PostForm("filename")
    filepath := path.Join(uploadDir, filename)  // Direct concatenation
    os.Remove(filepath)  // Arbitrary file deletion
    c.JSON(200, gin.H{"success": true})
}
```

#### Vulnerable Code Example (PHP)
```php
// High Risk: Directly deleting user-specified files
function deleteFile($filename) {
    $filepath = UPLOAD_DIR . '/' . $filename;  // Direct concatenation
    unlink($filepath);  // Arbitrary file deletion
}
```

#### Vulnerable Code Example (Node.js)
```javascript
// High Risk: Path traversal deletion
app.post('/delete', (req, res) => {
    const filename = req.body.filename;
    const filepath = path.join(uploadDir, filename);  // Direct concatenation
    fs.unlinkSync(filepath);  // Arbitrary file deletion
    res.json({ success: true });
});
```

### Multi-Language Detection Commands

```bash
# ========== Java ==========
# File deletion interface detection
grep -rn "Files\.delete\|FileUtils\.delete\|\.delete()" --include="*.java"

# Delete API endpoints
grep -rn "@.*Mapping.*delete\|@DeleteMapping" --include="*.java" -A 5

# Storage/File service delete methods
grep -rn "void\s+delete.*String\s+\(filename\|key\|path\)" --include="*.java"

# ========== Python ==========
# File deletion operations
grep -rn "os\.remove\|os\.unlink\|shutil\.rmtree\|Path.*unlink" --include="*.py"

# Flask/Django delete endpoints
grep -rn "@.*route.*delete\|def delete" --include="*.py" -A 5

# ========== Go ==========
# File deletion operations
grep -rn "os\.Remove\|os\.RemoveAll" --include="*.go"

# Gin/Echo delete endpoints
grep -rn "DELETE\|\.Delete(" --include="*.go" -A 5

# ========== PHP ==========
# File deletion functions
grep -rn "unlink\|rmdir\|array_map.*unlink" --include="*.php"

# Delete interfaces
grep -rn "function\s+delete\|action.*delete" --include="*.php" -A 5

# ========== Node.js ==========
# File deletion operations
grep -rn "fs\.unlink\|fs\.rm\|fs\.rmSync\|rimraf" --include="*.js" --include="*.ts"

# Express delete routes
grep -rn "\.delete\s*(\|router\.delete" --include="*.js" --include="*.ts" -A 5
```

### Security Fix Solution

```java
// Secure: Path normalization + whitelist directory validation
public void deleteSafe(String filename) {
    // 1. Path normalization
    Path basePath = Paths.get(rootLocation).normalize().toAbsolutePath();
    Path filePath = basePath.resolve(filename).normalize().toAbsolutePath();

    // 2. Check if within allowed directory
    if (!filePath.startsWith(basePath)) {
        throw new SecurityException("Invalid file path: path traversal detected");
    }

    // 3. Check file existence
    if (!Files.exists(filePath)) {
        throw new FileNotFoundException("File not found");
    }

    // 4. Optional: Check file type whitelist
    String extension = getFileExtension(filename);
    if (!ALLOWED_DELETE_EXTENSIONS.contains(extension)) {
        throw new SecurityException("File type not allowed for deletion");
    }

    // 5. Audit log
    auditLog.info("File deleted: {} by user: {}", filePath, getCurrentUser());

    // 6. Execute deletion
    Files.delete(filePath);
}
```

---

## File CRUD Completeness Checklist (v2.5.0 New)

> **Core Principle**: When auditing file operations, you must cover all Create/Read/Update/Delete operations; do not only focus on upload and download!

### CRUD Operation Comparison Table

| Operation | Typical Functions | Common Vulnerabilities | Detection Priority |
|-----------|------------------|----------------------|-------------------|
| **Create (Upload)** | upload, save, write, create | Arbitrary file upload, path traversal write | High |
| **Read (Download)** | download, read, get, fetch | Arbitrary file read, path traversal | High |
| **Update (Overwrite)** | update, replace, overwrite | Arbitrary file overwrite | Medium |
| **Delete (Deletion)** | delete, remove, unlink | Arbitrary file deletion | High (Easily missed!) |

### Multi-Language CRUD Detection Commands

```bash
# ========== Comprehensive Detection (All Languages) ==========
# File operation entry point enumeration
grep -rn "upload\|download\|delete\|remove\|read\|write\|save" \
  --include="*.java" --include="*.py" --include="*.go" \
  --include="*.php" --include="*.js" --include="*.ts" \
  | grep -i "file\|storage\|attachment"

# ========== Java Complete Detection ==========
# Create
grep -rn "MultipartFile\|transferTo\|Files\.write\|FileOutputStream" --include="*.java"
# Read
grep -rn "FileInputStream\|Files\.read\|FileUtils\.read" --include="*.java"
# Update
grep -rn "Files\.write.*TRUNCATE\|FileWriter\|overwrite" --include="*.java"
# Delete
grep -rn "Files\.delete\|FileUtils\.delete\|\.delete()" --include="*.java"

# ========== Python Complete Detection ==========
# Create
grep -rn "\.save\(\|open.*'w'\|shutil\.copy" --include="*.py"
# Read
grep -rn "open.*'r'\|\.read\(\|Path.*read" --include="*.py"
# Update
grep -rn "open.*'w'\|\.write\(" --include="*.py"
# Delete
grep -rn "os\.remove\|os\.unlink\|shutil\.rmtree\|Path.*unlink" --include="*.py"

# ========== Go Complete Detection ==========
# Create
grep -rn "os\.Create\|ioutil\.WriteFile\|os\.OpenFile" --include="*.go"
# Read
grep -rn "os\.Open\|ioutil\.ReadFile\|os\.ReadFile" --include="*.go"
# Update
grep -rn "os\.OpenFile.*O_WRONLY\|os\.Truncate" --include="*.go"
# Delete
grep -rn "os\.Remove\|os\.RemoveAll" --include="*.go"

# ========== PHP Complete Detection ==========
# Create
grep -rn "move_uploaded_file\|file_put_contents\|fwrite" --include="*.php"
# Read
grep -rn "file_get_contents\|fread\|readfile" --include="*.php"
# Update
grep -rn "file_put_contents\|fwrite" --include="*.php"
# Delete
grep -rn "unlink\|rmdir\|array_map.*unlink" --include="*.php"

# ========== Node.js Complete Detection ==========
# Create
grep -rn "fs\.writeFile\|createWriteStream\|\.pipe(" --include="*.js" --include="*.ts"
# Read
grep -rn "fs\.readFile\|createReadStream" --include="*.js" --include="*.ts"
# Update
grep -rn "fs\.writeFile\|fs\.truncate" --include="*.js" --include="*.ts"
# Delete
grep -rn "fs\.unlink\|fs\.rm\|rimraf" --include="*.js" --include="*.ts"
```

### Audit Completion Check Matrix

```markdown
## File Operations CRUD Coverage Verification

| Operation Type | Entry Points Found | Analyzed | Vulnerable | Secure | Coverage |
|---------------|-------------------|----------|-----------|--------|----------|
| Create (Upload) | _ | _ | _ | _ | _% |
| Read (Download) | _ | _ | _ | _ | _% |
| Update (Overwrite) | _ | _ | _ | _ | _% |
| Delete (Deletion) | _ | _ | _ | _ | _% |
| **Total** | _ | _ | _ | _ | _% |

Must reach 100% coverage to complete the file operations audit!
```

---

## References

### Security Standards
- OWASP Path Traversal: https://owasp.org/www-community/attacks/Path_Traversal
- CWE-22: Improper Limitation of a Pathname to a Restricted Directory
- CWE-73: External Control of File Name or Path
- **CWE-377: Insecure Temporary File** (related to file deletion)
- **CWE-379: Creation of Temporary File in Directory with Insecure Permissions**

### Tool References
- Semgrep file operation rules: https://semgrep.dev/r/java
- CodeQL path traversal queries: https://codeql.github.com/codeql-query-help/java/

### Real-World Case References
- **litemall GitHub #564**: Arbitrary file deletion vulnerability (LocalStorage.java path traversal)
