VYPR
Critical severityNVD Advisory· Published Aug 20, 2025· Updated Aug 20, 2025

Directus allows unauthenticated file upload and file modification due to lacking input sanitization

CVE-2025-55746

Description

Directus is a real-time API and App dashboard for managing SQL database content. From 10.8.0 to before 11.9.3, a vulnerability exists in the file update mechanism which allows an unauthenticated actor to modify existing files with arbitrary contents (without changes being applied to the files' database-resident metadata) and / or upload new files, with arbitrary content and extensions, which won't show up in the Directus UI. This vulnerability is fixed in 11.9.3.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
directusnpm
>= 10.8.0, < 11.9.311.9.3
@directus/apinpm
>= 14.1.0, < 28.0.228.0.2

Affected products

1

Patches

1
d84dcc36f75f

Merge commit from fork

https://github.com/directus/directusBrainslugJul 9, 2025via ghsa
1 file changed · +17 10
  • api/src/services/files.ts+17 10 modified
    @@ -79,16 +79,18 @@ export class FilesService extends ItemsService<File> {
     		const fileExtension =
     			path.extname(payload.filename_download!) || (payload.type && '.' + extension(payload.type)) || '';
     
    +		const filenameDisk = primaryKey + (fileExtension || '');
    +
     		// The filename_disk is the FINAL filename on disk
    -		payload.filename_disk ||= primaryKey + (fileExtension || '');
    +		payload.filename_disk ||= filenameDisk;
     
     		// If the filename_disk extension doesn't match the new mimetype, update it
     		if (isReplacement === true && path.extname(payload.filename_disk!) !== fileExtension) {
    -			payload.filename_disk = primaryKey + (fileExtension || '');
    +			payload.filename_disk = filenameDisk;
     		}
     
     		// Temp filename is used for replacements
    -		const tempFilenameDisk = 'temp_' + payload.filename_disk;
    +		const tempFilenameDisk = 'temp_' + filenameDisk;
     
     		if (!payload.type) {
     			payload.type = 'application/octet-stream';
    @@ -147,15 +149,20 @@ export class FilesService extends ItemsService<File> {
     
     		// If the file is a replacement, we need to update the DB record with the new payload, delete the old files, and upgrade the temp file
     		if (isReplacement === true) {
    -			await this.updateOne(primaryKey, payload, { emitEvents: false });
    +			try {
    +				await this.updateOne(primaryKey, payload, { emitEvents: false });
     
    -			// delete the previously saved file and thumbnails to ensure they're generated fresh
    -			for await (const filepath of disk.list(String(primaryKey))) {
    -				await disk.delete(filepath);
    -			}
    +				// delete the previously saved file and thumbnails to ensure they're generated fresh
    +				for await (const filepath of disk.list(String(primaryKey))) {
    +					await disk.delete(filepath);
    +				}
     
    -			// Upgrade the temp file to the final filename
    -			await disk.move(tempFilenameDisk, payload.filename_disk);
    +				// Upgrade the temp file to the final filename
    +				await disk.move(tempFilenameDisk, payload.filename_disk);
    +			} catch (err: any) {
    +				await cleanUp();
    +				throw err;
    +			}
     		}
     
     		const { size } = await storage.location(data.storage).stat(payload.filename_disk);
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.