Skip to content

[BUG] LFI Vulnerability via Unsanitized File Path in Upload and Download Handlers #1462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

geckosecurity
Copy link

Version: 0.0.14

Description

A critical Local File Inclusion (LFI) vulnerability exists in SuperAGI’s file handling mechanism. The application does not properly sanitize file paths during both upload and download operations, allowing attackers to read arbitrary files from the server.

The issue stems from two endpoints: the upload endpoint (/add/<agent_id>) and the download endpoint (/get/<resource_id>), both located in superagi/controllers/resources.py.

During upload, user-supplied filenames are accepted via multipart/form-data and directly joined with a base directory using os.path.join() without validating the full path. The resulting path is stored in the database.

Later, the download endpoint retrieves this path from the database and uses it to read the file. Although it calls Path().resolve() during the read operation, the path has already been constructed and trusted. This enables attackers to:

  • Upload a file with a malicious path like ../../../../etc/passwd.txt.
  • Cause the server to store that path.
  • Retrieve the file using the download endpoint, resulting in LFI.

Source - Sink Analysis

  1. Source: upload() in superagi/controllers/resources.py

    • Accepts user-controlled filename via HTTP POST.
  2. Intermediate: os.path.join() in resources.py

    • Joins untrusted input to build file path without validation.
  3. Sink (Write): open() in resources.py

    • Saves file to the filesystem using crafted path.
  4. Sink (Read): Path.resolve() in resources.py

    • Loads file using the stored path, leading to LFI.

Proof of Concept

1. Upload a file with a malicious name:

touch anyfile.txt
echo "This is a test file" > anyfile.txt

curl -X POST "http://127.0.0.1:3000/api/resources/add/1" \
  -H "Content-Type: multipart/form-data" \
  -F "[email protected]" \
  -F "name=../../../../etc/passwd.txt" \
  -F "type=text/plain" \
  -F "size=1024"

2. Retrieve the file via the download endpoint:

curl -X GET "http://127.0.0.1:3000/api/resources/get/20"

# Output: This is a test file

This confirms that arbitrary files can be read through crafted upload paths, allowing an attacker to access sensitive system files or previously overwritten files via AFO.

Impact

This vulnerability allows attackers to:

  • Access sensitive files on the host filesystem.
  • Combine with AFO (Arbitrary File Overwrite) to upload and then read crafted files.
  • Bypass security controls that rely on path restrictions.

@geckosecurity
Copy link
Author

Hi! Are there any updates on the review of the vulnerability?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants