Broken Function Level Authorization

Broken Function Level Authorization in Laravel [Mar 2026] [CVE-2017-14704]

[Fixed Mar 2026] Updated CVE-2017-14704

Overview

The CVE-2017-14704 case illustrates a real-world threat where a Laravel-based app (Claydip Laravel Airbnb Clone 1.0) allowed remote authenticated users to upload files through endpoints like imageSubmit and proof_submit, store them in a public web directory, and then access those files directly via a URL under images/profile. By not validating upload types, not enforcing authorization on both upload and direct access, and by placing uploaded content in the public web root, attackers could upload executable PHP code and trigger remote code execution simply by requesting the file. This highlights a Broken Function Level Authorization risk where access to endpoints and the resulting artifacts (uploaded files) are not properly guarded, enabling privilege abuse and direct manipulation of application resources (CWE-434 Unrestricted Upload of File with Dangerous Type). Reference CVE-2017-14704 demonstrates how misconfigurations around file handling and direct object access can lead to severe compromises in a Laravel-based system.

Affected Versions

Claydip Laravel Airbnb Clone 1.0

Code Fix Example

Laravel API Security Remediation
Vulnerable pattern:
// app/Http/Controllers/UploadController.php
public function imageSubmit(Request $request) {
  if ($request->hasFile('imageSubmit')) {
    $file = $request->file('imageSubmit');
    $destination = public_path('images/profile');
    $file->move($destination, $file->getClientOriginalName());
  }
  return response()->json(['status' => 'ok']);
}

Fixed pattern:
// app/Http/Controllers/UploadController.php
// Ensure a non-public disk is configured, e.g., in config/filesystems.php:
// 'private' => [ 'driver' => 'local', 'root' => storage_path('app/private'), 'visibility' => 'private' ],
public function imageSubmit(Request $request)
{
  // Function-level authorization check
  $this->authorize('uploadProfileImage', auth()->user());

  // Validate file type and size strictly
  $request->validate([
    'imageSubmit' => 'required|file|mimes:jpg,jpeg,png,bmp,gif,svg,webp|max:2048'
  ]);

  // Store outside web root to prevent execution via direct URL
  $path = $request->file('imageSubmit')->store('uploads/profile', ['disk' => 'private']);

  // Return a non-direct link or identifier; actual serving should be through a controller action with auth
  return response()->json(['path' => $path]);
}

public function showProfileImage($filename)
{
  // Securely serve the file after authorization
  $this->authorize('viewProfileImage', auth()->user());
  $path = storage_path('app/private/uploads/profile/'.$filename);
  if (!File::exists($path)) {
    abort(404);
  }
  return response()->file($path);
}

CVE References

Choose which optional cookies to allow. You can change this any time.