VYPR
Moderate severityNVD Advisory· Published Aug 22, 2025· Updated Aug 22, 2025

CVE-2025-43752

CVE-2025-43752

Description

Liferay Portal 7.4.0 through 7.4.3.132, and Liferay DXP 2025.Q1.0 through 2025.Q1.4, 2024.Q4.0 through 2024.Q4.7, 2024.Q3.1 through 2024.Q3.13, 2024.Q2.0 through 2024.Q2.13, 2024.Q1.1 through 2024.Q1.15 and 7.4 GA through update 92 allow users to upload an unlimited amount of files through the object entries attachment fields, the files are stored in the document_library allowing an attacker to cause a potential DDoS.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
com.liferay.portal:release.portal.bomMaven
>= 7.4.0-ga1, <= 7.4.3.132-ga132

Affected products

2

Patches

3
45dda30252d8

LPD-49638 Add playwright test

https://github.com/liferay/liferay-portalCarolina BarbosaFeb 26, 2025via ghsa
4 files changed · +141 0
  • modules/test/playwright/helpers/HeadlessDeliveryApiHelper.ts+6 0 modified
    @@ -108,6 +108,12 @@ export class HeadlessDeliveryApiHelper {
     		);
     	}
     
    +	async getDocument(documentId: string) {
    +		return this.apiHelpers.get(
    +			`${this.apiHelpers.baseUrl}${this.basePath}/documents/${documentId}`
    +		);
    +	}
    +
     	async getSiteDocumentsPage(siteId: string, sort: string = 'id') {
     		return this.apiHelpers.get(
     			`${this.apiHelpers.baseUrl}${this.basePath}/sites/${siteId}/documents?sort=${sort}`
    
  • modules/test/playwright/pages/object-web/object-entries/ViewObjectEntriesPage.ts+15 0 modified
    @@ -5,6 +5,7 @@
     
     import {ObjectField} from '@liferay/object-admin-rest-client-js';
     import {FrameLocator, Locator, Page, expect} from '@playwright/test';
    +import path from 'path';
     
     import {PORTLET_URLS} from '../../../utils/portletUrls';
     
    @@ -181,6 +182,20 @@ export class ViewObjectEntriesPage {
     			.click();
     	}
     
    +	async selectFileFromUserComputer(dirName: string, fileName: string) {
    +		const fileChooserPromise = this.page.waitForEvent('filechooser');
    +
    +		await this.selectFileButton.click();
    +
    +		const fileChooser = await fileChooserPromise;
    +
    +		await fileChooser.setFiles(
    +			path.join(dirName, 'dependencies', fileName)
    +		);
    +
    +		await this.page.getByText(fileName).waitFor({state: 'visible'});
    +	}
    +
     	async goto(
     		objectDefinitionClassName: string,
     		regionalCode?: string,
    
  • modules/test/playwright/tests/object-web/dependencies/astronaut.png+0 0 added
  • modules/test/playwright/tests/object-web/objectEntries.spec.ts+120 0 modified
    @@ -1455,6 +1455,126 @@ test.describe('Manage object entries through View Object Entries', () => {
     			'Entry A'
     		);
     	});
    +
    +	test('Verify that temporary files are deleted from the database if the object creation is not completed', async ({
    +		apiHelpers,
    +		page,
    +		viewObjectEntriesPage,
    +	}) => {
    +
    +		// Create object definition with attachment object field
    +
    +		const objectDefinition =
    +			await apiHelpers.objectAdmin.postRandomObjectDefinition({
    +				objectFields: [mockedObjectFields.attachmentFieldUserComputer],
    +				objectFolderExternalReferenceCode: 'default',
    +				status: {code: 0},
    +			});
    +
    +		apiHelpers.data.push({
    +			id: objectDefinition.id,
    +			type: 'objectDefinition',
    +		});
    +
    +		await viewObjectEntriesPage.goto(objectDefinition.className);
    +
    +		await viewObjectEntriesPage.clickAddObjectEntry(objectDefinition.name);
    +
    +		// Upload first file from user computer
    +
    +		await viewObjectEntriesPage.selectFileFromUserComputer(
    +			__dirname,
    +			'sampleFile.txt'
    +		);
    +
    +		const fileEntryId1 = await page.getAttribute(
    +			'input[data-field-name^="testAttachment"]',
    +			'value'
    +		);
    +
    +		expect(
    +			await apiHelpers.headlessDelivery.getDocument(fileEntryId1)
    +		).toEqual(
    +			expect.objectContaining({
    +				id: Number(fileEntryId1),
    +			})
    +		);
    +
    +		// Verify that the first file is removed after the second file is uploaded
    +
    +		await viewObjectEntriesPage.selectFileFromUserComputer(
    +			__dirname,
    +			'astronaut.png'
    +		);
    +
    +		expect(
    +			await apiHelpers.headlessDelivery.getDocument(fileEntryId1)
    +		).toEqual({status: 'NOT_FOUND'});
    +
    +		const fileEntryId2 = await page.getAttribute(
    +			'input[data-field-name^="testAttachment"]',
    +			'value'
    +		);
    +
    +		expect(
    +			await apiHelpers.headlessDelivery.getDocument(fileEntryId2)
    +		).toEqual(
    +			expect.objectContaining({
    +				id: Number(fileEntryId2),
    +			})
    +		);
    +
    +		// Verify that the delete button removes the second file
    +
    +		await viewObjectEntriesPage.deleteFileButton.click();
    +
    +		expect(
    +			await apiHelpers.headlessDelivery.getDocument(fileEntryId2)
    +		).toEqual({status: 'NOT_FOUND'});
    +
    +		// Verify that the file is removed after page reload
    +
    +		await viewObjectEntriesPage.selectFileFromUserComputer(
    +			__dirname,
    +			'sampleFile.txt'
    +		);
    +
    +		const fileEntryId3 = await page.getAttribute(
    +			'input[data-field-name^="testAttachment"]',
    +			'value'
    +		);
    +
    +		await page.reload();
    +
    +		expect(
    +			await apiHelpers.headlessDelivery.getDocument(fileEntryId3)
    +		).toEqual({status: 'NOT_FOUND'});
    +
    +		// Verify that the file is saved successfully when clicking submit
    +
    +		await viewObjectEntriesPage.selectFileFromUserComputer(
    +			__dirname,
    +			'astronaut.png'
    +		);
    +
    +		await viewObjectEntriesPage.saveObjectEntryButton.click();
    +
    +		await expect(viewObjectEntriesPage.successMessage).toBeVisible();
    +		await expect(
    +			viewObjectEntriesPage.page.getByText('astronaut.png')
    +		).toBeVisible();
    +
    +		await viewObjectEntriesPage.selectFileFromUserComputer(
    +			__dirname,
    +			'sampleFile.txt'
    +		);
    +
    +		await page.reload();
    +
    +		await expect(
    +			viewObjectEntriesPage.page.getByText('astronaut.png')
    +		).toBeVisible();
    +	});
     });
     
     test.describe('Manage object entries through Workflow', () => {
    
f3e4723acdf1

LPD-49638 Delete current file entry when the user clicks the delete button, selects a new file, or refreshes the page

https://github.com/liferay/liferay-portalCarolina BarbosaFeb 26, 2025via ghsa
3 files changed · +68 2
  • modules/apps/object/object-dynamic-data-mapping-form-field-type/src/main/resources/META-INF/resources/js/Attachment/AttachmentBase.tsx+7 1 modified
    @@ -21,6 +21,7 @@ import {LocalizedValue} from 'dynamic-data-mapping-form-field-type/src/main/reso
     
     export type AttachmentFile = {
     	contentURL: string;
    +	fileEntryId: string;
     	title: string;
     };
     
    @@ -90,6 +91,7 @@ export default function AttachmentBase({
     			onAttachmentChange(
     				{
     					contentURL: selectedItemValue.url,
    +					fileEntryId: selectedItemValue.fileEntryId,
     					title: selectedItemValue.title,
     				},
     				selectedItemValue.fileEntryId
    @@ -133,7 +135,11 @@ export default function AttachmentBase({
     				}
     				else {
     					onAttachmentChange(
    -						{contentURL: file.contentURL, title: file.title},
    +						{
    +							contentURL: file.contentURL,
    +							fileEntryId: file.fileEntryId,
    +							title: file.title,
    +						},
     						file.fileEntryId
     					);
     				}
    
  • modules/apps/object/object-dynamic-data-mapping-form-field-type/src/main/resources/META-INF/resources/js/Attachment/Attachment.tsx+59 1 modified
    @@ -3,6 +3,7 @@
      * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
      */
     
    +import {useConfig} from 'data-engine-js-components-web';
     import {ReactFieldBase as FieldBase} from 'dynamic-data-mapping-form-field-type';
     import {
     	FieldChangeEventHandler,
    @@ -12,7 +13,8 @@ import {
     	AvailableLocale,
     	EditingLocale,
     } from 'dynamic-data-mapping-form-field-type/src/main/resources/META-INF/resources/util/localizable/LocalesDropdown';
    -import React, {useState} from 'react';
    +import {fetch} from 'frontend-js-web';
    +import React, {useCallback, useEffect, useState} from 'react';
     
     import AttachmentBase, {
     	AttachmentBaseProps,
    @@ -25,6 +27,7 @@ export interface AttachmentProps
     	availableLocales: AvailableLocale[];
     	contentURL?: string;
     	defaultLocale: EditingLocale;
    +	deleteURL?: string;
     	fieldName: string;
     	fileEntryProperties: AttachmentFile | LocalizedValue<AttachmentFile>;
     	localizedObjectField: boolean;
    @@ -34,6 +37,7 @@ export interface AttachmentProps
     
     export default function Attachment({
     	contentURL,
    +	deleteURL,
     	fileEntryProperties,
     	localizedObjectField,
     	onChange,
    @@ -46,6 +50,8 @@ export default function Attachment({
     	const isLocalizedObjectField: boolean =
     		Liferay.FeatureFlags['LPD-32050'] && !!localizedObjectField;
     
    +	const {portletNamespace} = useConfig();
    +
     	const getAttachment = () => {
     		if (Liferay.FeatureFlags['LPD-32050']) {
     			return fileEntryProperties;
    @@ -61,17 +67,69 @@ export default function Attachment({
     		getAttachment() as AttachmentFile | null
     	);
     	const [error, setError] = useState({});
    +	const [submitButtonClicked, setSubmitButtonClicked] = useState(false);
    +
    +	const deleteFileEntry = useCallback(async () => {
    +		if (!attachment || !deleteURL) {
    +			return;
    +		}
    +
    +		const {fileEntryId} = attachment;
    +
    +		if (!fileEntryId) {
    +			return;
    +		}
    +
    +		const formData = new FormData();
    +
    +		formData.append(`${portletNamespace}fileEntryId`, fileEntryId);
    +
    +		await fetch(deleteURL, {
    +			body: formData,
    +			method: 'POST',
    +		});
    +	}, [attachment, deleteURL, portletNamespace]);
    +
    +	useEffect(() => {
    +		window.onbeforeunload = function () {
    +			if (!submitButtonClicked) {
    +				deleteFileEntry();
    +			}
    +		};
    +
    +		return () => {
    +			window.onbeforeunload = null;
    +		};
    +	}, [deleteFileEntry, submitButtonClicked]);
    +
    +	useEffect(() => {
    +		Liferay.on(
    +			'submitButtonClicked',
    +
    +			() => {
    +				setSubmitButtonClicked(true);
    +			}
    +		);
    +
    +		return () => {
    +			Liferay.detach('submitButtonClicked');
    +		};
    +	}, []);
     
     	const handleAttachmentChange = (
     		attachmentValue: AttachmentFile,
     		fileId: string
     	) => {
    +		deleteFileEntry();
    +
     		setAttachment(attachmentValue);
     
     		onChange({target: {value: fileId}});
     	};
     
     	const handleDelete = () => {
    +		deleteFileEntry();
    +
     		setAttachment(null);
     
     		onChange({target: {value: ''}}); // TODO: fix backend to support null
    
  • modules/apps/object/object-web/src/main/resources/META-INF/resources/object_entries/object_entry/form.jsp+2 0 modified
    @@ -252,6 +252,8 @@ portletDisplay.setURLBack(backURL);
     							method: externalReferenceCode ? 'PATCH' : 'POST',
     						})
     							.then((response) => {
    +								Liferay.fire('submitButtonClicked');
    +
     								if (response.status === 401) {
     									window.location.reload();
     								}
    
fffed67b3fd1

LPD-49638 Add new MVCActionCommand to delete file entry

https://github.com/liferay/liferay-portalCarolina BarbosaFeb 26, 2025via ghsa
3 files changed · +101 0
  • modules/apps/object/object-dynamic-data-mapping-form-field-type/src/main/java/com/liferay/object/dynamic/data/mapping/form/field/type/internal/attachment/AttachmentDDMFormFieldTemplateContextContributor.java+23 0 modified
    @@ -17,6 +17,7 @@
     import com.liferay.item.selector.criteria.FileEntryItemSelectorReturnType;
     import com.liferay.item.selector.criteria.file.criterion.FileItemSelectorCriterion;
     import com.liferay.object.configuration.ObjectConfiguration;
    +import com.liferay.object.constants.ObjectFieldSettingConstants;
     import com.liferay.object.dynamic.data.mapping.form.field.type.constants.ObjectDDMFormFieldTypeConstants;
     import com.liferay.petra.string.StringPool;
     import com.liferay.portal.configuration.metatype.bnd.util.ConfigurableUtil;
    @@ -73,6 +74,28 @@ public Map<String, Object> getParameters(
     		Map<String, Object> parameters = HashMapBuilder.<String, Object>put(
     			"acceptedFileExtensions",
     			ddmFormField.getProperty("acceptedFileExtensions")
    +		).put(
    +			"deleteURL",
    +			() -> {
    +				if (!Objects.equals(
    +						ddmFormField.getProperty("fileSource"),
    +						ObjectFieldSettingConstants.VALUE_USER_COMPUTER)) {
    +
    +					return null;
    +				}
    +
    +				RequestBackedPortletURLFactory requestBackedPortletURLFactory =
    +					RequestBackedPortletURLFactoryUtil.create(
    +						ddmFormFieldRenderingContext.getHttpServletRequest());
    +
    +				return PortletURLBuilder.create(
    +					requestBackedPortletURLFactory.createActionURL(
    +						GetterUtil.getString(
    +							ddmFormField.getProperty("portletId")))
    +				).setActionName(
    +					"/object_entries/delete_attachment"
    +				).buildString();
    +			}
     		).put(
     			"fileSource", ddmFormField.getProperty("fileSource")
     		).put(
    
  • modules/apps/object/object-web/src/main/java/com/liferay/object/web/internal/deployer/ObjectDefinitionDeployerImpl.java+14 0 modified
    @@ -15,6 +15,7 @@
     import com.liferay.document.library.kernel.exception.FileSizeException;
     import com.liferay.document.library.kernel.exception.InvalidFileException;
     import com.liferay.document.library.kernel.service.DLAppLocalService;
    +import com.liferay.document.library.kernel.service.DLFileEntryLocalService;
     import com.liferay.document.library.util.DLURLHelper;
     import com.liferay.friendly.url.info.item.provider.InfoItemFriendlyURLProvider;
     import com.liferay.friendly.url.info.item.updater.InfoItemFriendlyURLUpdater;
    @@ -111,6 +112,7 @@
     import com.liferay.object.web.internal.object.entries.frontend.data.set.filter.factory.ObjectFieldFDSFilterFactoryRegistry;
     import com.liferay.object.web.internal.object.entries.frontend.data.set.view.table.ObjectEntriesTableFDSView;
     import com.liferay.object.web.internal.object.entries.portlet.ObjectEntriesPortlet;
    +import com.liferay.object.web.internal.object.entries.portlet.action.DeleteAttachmentMVCActionCommand;
     import com.liferay.object.web.internal.object.entries.portlet.action.EditObjectEntryMVCActionCommand;
     import com.liferay.object.web.internal.object.entries.portlet.action.EditObjectEntryMVCRenderCommand;
     import com.liferay.object.web.internal.object.entries.portlet.action.EditObjectEntryRelatedModelMVCActionCommand;
    @@ -527,6 +529,15 @@ public List<ServiceRegistration<?>> deploy(
     				).put(
     					"javax.portlet.version", "3.0"
     				).build()),
    +			_bundleContext.registerService(
    +				MVCActionCommand.class,
    +				new DeleteAttachmentMVCActionCommand(
    +					_dlFileEntryLocalService, objectDefinition),
    +				HashMapDictionaryBuilder.<String, Object>put(
    +					"javax.portlet.name", objectDefinition.getPortletId()
    +				).put(
    +					"mvc.command.name", "/object_entries/delete_attachment"
    +				).build()),
     			_bundleContext.registerService(
     				MVCActionCommand.class,
     				new EditObjectEntryMVCActionCommand(
    @@ -726,6 +737,9 @@ private String _getResourceName(ObjectDefinition objectDefinition) {
     	@Reference
     	private DLAppLocalService _dlAppLocalService;
     
    +	@Reference
    +	private DLFileEntryLocalService _dlFileEntryLocalService;
    +
     	@Reference
     	private DLURLHelper _dlURLHelper;
     
    
  • modules/apps/object/object-web/src/main/java/com/liferay/object/web/internal/object/entries/portlet/action/DeleteAttachmentMVCActionCommand.java+64 0 added
    @@ -0,0 +1,64 @@
    +/**
    + * SPDX-FileCopyrightText: (c) 2025 Liferay, Inc. https://liferay.com
    + * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
    + */
    +
    +package com.liferay.object.web.internal.object.entries.portlet.action;
    +
    +import com.liferay.document.library.kernel.model.DLFileEntry;
    +import com.liferay.document.library.kernel.model.DLFolder;
    +import com.liferay.document.library.kernel.service.DLFileEntryLocalService;
    +import com.liferay.object.model.ObjectDefinition;
    +import com.liferay.portal.kernel.portlet.bridges.mvc.BaseMVCActionCommand;
    +import com.liferay.portal.kernel.util.ParamUtil;
    +import com.liferay.portal.kernel.util.StringUtil;
    +
    +import javax.portlet.ActionRequest;
    +import javax.portlet.ActionResponse;
    +
    +/**
    + * @author Carolina Barbosa
    + */
    +public class DeleteAttachmentMVCActionCommand extends BaseMVCActionCommand {
    +
    +	public DeleteAttachmentMVCActionCommand(
    +		DLFileEntryLocalService dlFileEntryLocalService,
    +		ObjectDefinition objectDefinition) {
    +
    +		_dlFileEntryLocalService = dlFileEntryLocalService;
    +		_objectDefinition = objectDefinition;
    +	}
    +
    +	@Override
    +	protected void doProcessAction(
    +			ActionRequest actionRequest, ActionResponse actionResponse)
    +		throws Exception {
    +
    +		long fileEntryId = ParamUtil.getLong(actionRequest, "fileEntryId");
    +
    +		if (fileEntryId == 0) {
    +			return;
    +		}
    +
    +		DLFileEntry dlFileEntry = _dlFileEntryLocalService.fetchDLFileEntry(
    +			fileEntryId);
    +
    +		if (dlFileEntry == null) {
    +			return;
    +		}
    +
    +		DLFolder dlFolder = dlFileEntry.getFolder();
    +
    +		if (!StringUtil.equals(
    +				dlFolder.getName(), _objectDefinition.getPortletId())) {
    +
    +			return;
    +		}
    +
    +		_dlFileEntryLocalService.deleteFileEntry(fileEntryId);
    +	}
    +
    +	private final DLFileEntryLocalService _dlFileEntryLocalService;
    +	private final ObjectDefinition _objectDefinition;
    +
    +}
    \ No newline at end of file
    

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

7

News mentions

0

No linked articles in our index yet.