Regarding File Security
File uploads are one of the most common attack vectors in web applications. A single malicious file can compromise your entire server. While Trongate provides strong automatic protections, understanding both what is handled for you and what requires your attention is essential for building secure applications.
What Trongate Handles Automatically
1. Path Validation
Every file operation (read, write, delete, etc.) inside the File module triggers a validation check to block directory traversal attempts and unauthorized access to system-critical areas.
// These attacks are automatically blocked:
$malicious = '../../../etc/passwd'; // Traversal
$malicious = '/absolute/system/path'; // Outside application scope
$malicious = 'config/database.php'; // Restricted system directory
$malicious = 'file.php\x00.jpg'; // Null byte injection
// All would throw: "Access to this path is restricted"
$this->file->read($malicious);Protected areas: The config and engine directories are completely off-limits. Files directly under your application root (such as .htaccess) are also protected from manipulation via the File class.
2. File Content Scanning
Content scanning happens during validation (), not during the upload itself. The Validation module reads the first 4,096 bytes of every uploaded file and checks for dangerous PHP or system patterns. If a threat is detected, the upload is blocked before the file can reach its destination.
// These patterns trigger automatic rejection:
'<?php' // PHP opening tag
'<![CDATA[' // CDATA sections
'<!DOCTYPE' // XML/HTML doctype
'eval(' // PHP eval()
'exec(' // System commands
'shell_exec(' // Shell execution
// Result: "A security threat was detected in the [label]. The upload has been blocked."How it works: When you set file validation rules via $this->validation->set_rules() followed by $this->validation->run(), the Validation module checks the temporary uploaded file for malicious content before ever touches it. This means a rejected file never leaves the temp directory.
3. MIME Type Verification
Trongate validates that files are what they claim to be. If a file has a .jpg extension but contains PHP binary signatures, the upload will be rejected immediately with a "MIME type mismatch" error.
What You Must Handle
1. File Size Limits
Always set explicit size limits in your validation rules to prevent Denial of Service (DoS) attacks via disk exhaustion.
// ✅ SECURE - explicit size limit (e.g., 5MB)
$this->validation->set_rules(
'userfile',
'File',
'allowed_types[pdf]|max_size[5120]'
);2. File Renaming
Never trust original filenames. Using random names prevents attackers from guessing file locations or overwriting existing system files.
// ✅ SECURE - random name
$config['make_rand_name'] = true;
// Result: attacker.pdf becomes x7f9d2e1b4a.pdf3. Directory Permissions
Always use the most restrictive permissions possible. While 0755 is standard for web-accessible folders, internal storage should be more restricted.
// Web-accessible: 0755 (Owner writes, others read)
$this->file->create_directory('public/uploads', 0755);
// Private storage: 0700 (Only PHP/Owner can access)
$this->file->create_directory('private/documents', 0700);NEVER use 0777 permissions on production servers. This allows any user on the system to write to or execute files in your directories.
Secure Upload Patterns
Pattern: Isolated User Workspaces
The most secure way to handle user files is to isolate them by ID and use random naming.
public function upload_user_file($user_id): void {
// 1. Define a user-specific path
$user_dir = "users/{$user_id}/" . date('Y/m');
// 2. Create the directory with secure permissions
$this->file->create_directory($user_dir, 0750);
// 3. Upload with security configurations
$config = [
'destination' => $user_dir,
'make_rand_name' => true,
'upload_to_module' => false
];
try {
$file_info = $this->file->upload($config);
// Store $file_info['file_path'] in your database
} catch (Exception $e) {
// Handle security rejections or upload errors
echo out($e->getMessage());
}
}Quick Security Checklist
- ✅ Validation: Are
max_sizeandallowed_typesset? - ✅ Names: Is
make_rand_nameset to true for user uploads? - ✅ Permissions: Are you using
0755or0700(and never0777)? - ✅ Storage: Are sensitive files stored outside of the public-facing directory?
- ✅ Sanitization: Are you using Trongate's function when rendering filenames in views?
We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.
Share your thoughts in the Documentation Feedback.