CVE-2023-44309
Description
Multiple stored cross-site scripting (XSS) vulnerabilities in the fragment components in Liferay Portal 7.4.2 through 7.4.3.53, and Liferay DXP 7.4 before update 54 allow remote attackers to inject arbitrary web script or HTML via a crafted payload injected into any non-HTML field of a linked source asset.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
com.liferay:com.liferay.fragment.entry.processor.implMaven | < 3.0.25 | 3.0.25 |
com.liferay.portal:release.dxp.bomMaven | >= 7.4.0, < 7.4.13.u54 | 7.4.13.u54 |
Affected products
2- Liferay/DXPv5Range: 7.4.13
Patches
71 file changed · +0 −2
modules/apps/fragment/fragment-entry-processor/fragment-entry-processor-test/src/testIntegration/java/com/liferay/fragment/entry/processor/internal/util/test/FragmentEntryProcessorHelperTest.java+0 −2 modified@@ -194,7 +194,6 @@ public void testGetFieldValueFromNullValue() throws Exception { public void testGetFieldValueFromStringValue() throws Exception { DDMFormField ddmFormField = _createDDMFormField( DDMFormFieldTypeConstants.TEXT); - String fieldValue = StringBundler.concat( "<script>alert(\"", RandomTestUtil.randomString(), "\")</script>"); @@ -223,7 +222,6 @@ public void testGetFieldValueFromStringValueRichTextDDMFormFieldType() DDMFormField ddmFormField = _createDDMFormField( DDMFormFieldTypeConstants.RICH_TEXT); - String fieldValue = StringBundler.concat( "<p>", RandomTestUtil.randomString(), "</p>");
1287c68486d6LPS-169645 The AssetCategory description is a rich text field so mark as HTML the description InfoField
1 file changed · +2 −0
modules/apps/asset/asset-categories-admin-web/src/main/java/com/liferay/asset/categories/admin/web/internal/info/item/AssetCategoryInfoItemFields.java+2 −0 modified@@ -29,6 +29,8 @@ public class AssetCategoryInfoItemFields { TextInfoFieldType.INSTANCE ).name( "description" + ).attribute( + TextInfoFieldType.HTML, true ).labelInfoLocalizedValue( InfoLocalizedValue.localize( AssetCategoryInfoItemFields.class, "description")
ed856dd9e294LPS-169645 Add required dependencies
1 file changed · +2 −0
modules/apps/fragment/fragment-entry-processor/fragment-entry-processor-test/build.gradle+2 −0 modified@@ -1,9 +1,11 @@ dependencies { testIntegrationCompile project(":apps:dynamic-data-mapping:dynamic-data-mapping-api") + testIntegrationCompile project(":apps:dynamic-data-mapping:dynamic-data-mapping-form-field-type-api") testIntegrationCompile project(":apps:dynamic-data-mapping:dynamic-data-mapping-test-util") testIntegrationCompile project(":apps:fragment:fragment-api") testIntegrationCompile project(":apps:fragment:fragment-entry-processor:fragment-entry-processor-api") testIntegrationCompile project(":apps:info:info-api") testIntegrationCompile project(":apps:journal:journal-api") + testIntegrationCompile project(":apps:journal:journal-test-util") testIntegrationCompile project(":test:arquillian-extension-junit-bridge") } \ No newline at end of file
d70fecd2c570LPS-169645 Add an integration test to assert that the String values are not escaped when the DDMFormFieldType is Rich Text
1 file changed · +29 −0
modules/apps/fragment/fragment-entry-processor/fragment-entry-processor-test/src/testIntegration/java/com/liferay/fragment/entry/processor/internal/util/test/FragmentEntryProcessorHelperTest.java+29 −0 modified@@ -217,6 +217,35 @@ public void testGetFieldValueFromStringValue() throws Exception { ))); } + @Test + public void testGetFieldValueFromStringValueRichTextDDMFormFieldType() + throws Exception { + + DDMFormField ddmFormField = _createDDMFormField( + DDMFormFieldTypeConstants.RICH_TEXT); + + String fieldValue = StringBundler.concat( + "<p>", RandomTestUtil.randomString(), "</p>"); + + JournalArticle journalArticle = JournalTestUtil.addJournalArticle( + ddmFormField, _ddmFormValuesToFieldsConverter, fieldValue, + _group.getGroupId(), _journalConverter); + + Assert.assertEquals( + fieldValue, + _getFieldValue( + JSONUtil.put( + "className", JournalArticle.class.getName() + ).put( + "classNameId", + _portal.getClassNameId(JournalArticle.class.getName()) + ).put( + "classPK", journalArticle.getResourcePrimKey() + ).put( + "fieldId", "DDMStructure_" + ddmFormField.getName() + ))); + } + @Test public void testGetFieldValueFromWebImage() throws Exception { String fieldId = "ImageFieldName";
28f8a7aabcccLPS-169645 Add an integration test to assert that the String values are escaped
1 file changed · +61 −0
modules/apps/fragment/fragment-entry-processor/fragment-entry-processor-test/src/testIntegration/java/com/liferay/fragment/entry/processor/internal/util/test/FragmentEntryProcessorHelperTest.java+61 −0 modified@@ -17,15 +17,19 @@ import com.liferay.arquillian.extension.junit.bridge.junit.Arquillian; import com.liferay.document.library.kernel.model.DLFolderConstants; import com.liferay.dynamic.data.mapping.constants.DDMStructureConstants; +import com.liferay.dynamic.data.mapping.form.field.type.constants.DDMFormFieldTypeConstants; import com.liferay.dynamic.data.mapping.io.DDMFormDeserializer; import com.liferay.dynamic.data.mapping.io.DDMFormDeserializerDeserializeRequest; import com.liferay.dynamic.data.mapping.io.DDMFormDeserializerDeserializeResponse; import com.liferay.dynamic.data.mapping.model.DDMForm; +import com.liferay.dynamic.data.mapping.model.DDMFormField; import com.liferay.dynamic.data.mapping.model.DDMStructure; import com.liferay.dynamic.data.mapping.model.DDMTemplate; +import com.liferay.dynamic.data.mapping.model.LocalizedValue; import com.liferay.dynamic.data.mapping.storage.StorageType; import com.liferay.dynamic.data.mapping.test.util.DDMStructureTestHelper; import com.liferay.dynamic.data.mapping.test.util.DDMTemplateTestUtil; +import com.liferay.dynamic.data.mapping.util.DDMFormValuesToFieldsConverter; import com.liferay.fragment.constants.FragmentEntryLinkConstants; import com.liferay.fragment.entry.processor.helper.FragmentEntryProcessorHelper; import com.liferay.fragment.processor.DefaultFragmentEntryProcessorContext; @@ -35,6 +39,8 @@ import com.liferay.journal.constants.JournalArticleConstants; import com.liferay.journal.model.JournalArticle; import com.liferay.journal.service.JournalArticleLocalService; +import com.liferay.journal.test.util.JournalTestUtil; +import com.liferay.journal.util.JournalConverter; import com.liferay.petra.io.unsync.UnsyncByteArrayInputStream; import com.liferay.petra.string.StringBundler; import com.liferay.petra.string.StringPool; @@ -57,6 +63,7 @@ import com.liferay.portal.kernel.util.ContentTypes; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.HashMapBuilder; +import com.liferay.portal.kernel.util.Html; import com.liferay.portal.kernel.util.LocaleUtil; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.StringUtil; @@ -183,6 +190,33 @@ public void testGetFieldValueFromNullValue() throws Exception { ))); } + @Test + public void testGetFieldValueFromStringValue() throws Exception { + DDMFormField ddmFormField = _createDDMFormField( + DDMFormFieldTypeConstants.TEXT); + + String fieldValue = StringBundler.concat( + "<script>alert(\"", RandomTestUtil.randomString(), "\")</script>"); + + JournalArticle journalArticle = JournalTestUtil.addJournalArticle( + ddmFormField, _ddmFormValuesToFieldsConverter, fieldValue, + _group.getGroupId(), _journalConverter); + + Assert.assertEquals( + _html.escape(fieldValue), + _getFieldValue( + JSONUtil.put( + "className", JournalArticle.class.getName() + ).put( + "classNameId", + _portal.getClassNameId(JournalArticle.class.getName()) + ).put( + "classPK", journalArticle.getResourcePrimKey() + ).put( + "fieldId", "DDMStructure_" + ddmFormField.getName() + ))); + } + @Test public void testGetFieldValueFromWebImage() throws Exception { String fieldId = "ImageFieldName"; @@ -397,6 +431,24 @@ private JournalArticle _addJournalArticle( return _addJournalArticle(ddmStructure, fieldId, fileEntry, title); } + private DDMFormField _createDDMFormField(String type) { + DDMFormField ddmFormField = new DDMFormField( + RandomTestUtil.randomString(10), type); + + ddmFormField.setDataType("text"); + ddmFormField.setIndexType("text"); + ddmFormField.setLocalizable(true); + + LocalizedValue localizedValue = new LocalizedValue(LocaleUtil.US); + + localizedValue.addString( + LocaleUtil.US, RandomTestUtil.randomString(10)); + + ddmFormField.setLabel(localizedValue); + + return ddmFormField; + } + private Document _createDocument( String availableLocales, String defaultLocale) { @@ -495,12 +547,21 @@ private String _readJSONFileToString(String jsonFileName) throws Exception { @Inject(filter = "ddm.form.deserializer.type=json") private static DDMFormDeserializer _jsonDDMFormDeserializer; + @Inject + private DDMFormValuesToFieldsConverter _ddmFormValuesToFieldsConverter; + @Inject private FragmentEntryProcessorHelper _fragmentEntryProcessorHelper; @DeleteAfterTestRun private Group _group; + @Inject + private Html _html; + + @Inject + private JournalConverter _journalConverter; + @Inject private Portal _portal;
e45bf2d00ed7LPS-169645 Reverse the condition: we should escape when isn't an HTML field
1 file changed · +1 −1
modules/apps/fragment/fragment-entry-processor/fragment-entry-processor-impl/src/main/java/com/liferay/fragment/entry/processor/internal/util/FragmentEntryProcessorHelperImpl.java+1 −1 modified@@ -503,7 +503,7 @@ private Object _getMappedInfoItemFieldValue( Optional<Boolean> htmlOptional = infoField.getAttributeOptional( TextInfoFieldType.HTML); - if (htmlOptional.orElse(false)) { + if (!htmlOptional.orElse(false)) { return _html.escape((String)value); } }
ba628735cfaeLPS-169645 Escape string
1 file changed · +17 −0
modules/apps/fragment/fragment-entry-processor/fragment-entry-processor-impl/src/main/java/com/liferay/fragment/entry/processor/internal/util/FragmentEntryProcessorHelperImpl.java+17 −0 modified@@ -17,7 +17,9 @@ import com.liferay.fragment.entry.processor.helper.FragmentEntryProcessorHelper; import com.liferay.fragment.processor.FragmentEntryProcessorContext; import com.liferay.info.exception.NoSuchInfoItemException; +import com.liferay.info.field.InfoField; import com.liferay.info.field.InfoFieldValue; +import com.liferay.info.field.type.TextInfoFieldType; import com.liferay.info.formatter.InfoCollectionTextFormatter; import com.liferay.info.formatter.InfoTextFormatter; import com.liferay.info.item.ClassPKInfoItemIdentifier; @@ -41,6 +43,7 @@ import com.liferay.portal.kernel.repository.model.FileEntry; import com.liferay.portal.kernel.trash.TrashHandler; import com.liferay.portal.kernel.trash.TrashHandlerRegistryUtil; +import com.liferay.portal.kernel.util.Html; import com.liferay.portal.kernel.util.LocaleUtil; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.Validator; @@ -494,6 +497,17 @@ private Object _getMappedInfoItemFieldValue( } if (value instanceof String) { + InfoField infoField = infoFieldValue.getInfoField(); + + if (infoField.getInfoFieldType() instanceof TextInfoFieldType) { + Optional<Boolean> htmlOptional = infoField.getAttributeOptional( + TextInfoFieldType.HTML); + + if (htmlOptional.orElse(false)) { + return _html.escape((String)value); + } + } + return (String)value; } @@ -533,6 +547,9 @@ private Object _getMappedInfoItemFieldValue( private static final Log _log = LogFactoryUtil.getLog( FragmentEntryProcessorHelperImpl.class); + @Reference + private Html _html; + @Reference private InfoItemServiceRegistry _infoItemServiceRegistry;
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
10- github.com/advisories/GHSA-j663-6jpj-xx8cghsaADVISORY
- liferay.dev/portal/security/known-vulnerabilities/-/asset_publisher/jekt/content/cve-2023-44309ghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2023-44309ghsaADVISORY
- github.com/liferay/liferay-portal/commit/1287c68486d60b87179995d8b8bd530031300a47ghsaWEB
- github.com/liferay/liferay-portal/commit/28f8a7aabccce45e9d60cfb0cf63fc53c99b0d26ghsaWEB
- github.com/liferay/liferay-portal/commit/9031a7a03e5891e7ccf762011fe8bcc2e433b1dbghsaWEB
- github.com/liferay/liferay-portal/commit/ba628735cfae8656ab4243ecffce260413ed2460ghsaWEB
- github.com/liferay/liferay-portal/commit/d70fecd2c5709d8dd5f4992b408a640ce912001bghsaWEB
- github.com/liferay/liferay-portal/commit/e45bf2d00ed7f95f02702a1da3e4115ab30b1bffghsaWEB
- github.com/liferay/liferay-portal/commit/ed856dd9e2947e3e660d7cfbdb8c604b296db790ghsaWEB
News mentions
0No linked articles in our index yet.