diff --git a/plugins/devkit/devkit-core/resources/inspectionDescriptions/WrongPluginModuleAlias.html b/plugins/devkit/devkit-core/resources/inspectionDescriptions/WrongPluginModuleAlias.html
new file mode 100644
index 000000000000..bfb1bbf02994
--- /dev/null
+++ b/plugins/devkit/devkit-core/resources/inspectionDescriptions/WrongPluginModuleAlias.html
@@ -0,0 +1,11 @@
+
+
+
+ Reports restricted plugin module aliases in non-JetBrains plugin descriptors.
+
+
+ Aliases starting with com.intellij.* are reserved for plugins developed by JetBrains and must not be declared
+ by third-party plugins.
+
+
+
diff --git a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
index 16012222ac3c..18741917a5ed 100644
--- a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
+++ b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
@@ -551,6 +551,13 @@
implementationClass="org.jetbrains.idea.devkit.inspections.ContentModuleNamespaceInspection"
key="inspection.content.module.namespace.name"/>
+
+
= module.value
+ val alias = value.value ?: return
+ if (alias.startsWith(reservedPrefix)) {
+ holder.createProblem(value, message("inspection.plugin.module.alias.message"))
+ }
+ }
+
+ private fun isDevelopedByJetBrains(element: PluginModule): Boolean {
+ val vendor = DomUtil.findDomElement(element.xmlElement, IdeaPlugin::class.java)?.vendor ?: return false
+ return PluginManagerCore.isDevelopedByJetBrains(vendor.stringValue)
+ }
+
+}
diff --git a/plugins/devkit/devkit-java-tests/BUILD.bazel b/plugins/devkit/devkit-java-tests/BUILD.bazel
index d495496675f8..2484f5d7a0c0 100644
--- a/plugins/devkit/devkit-java-tests/BUILD.bazel
+++ b/plugins/devkit/devkit-java-tests/BUILD.bazel
@@ -47,6 +47,7 @@ jvm_library(
"//plugins/devkit/devkit-tests:testFramework_test_lib",
"//platform/testFramework",
"//platform/testFramework:testFramework_test_lib",
+ "//platform/testFramework/junit5/codeInsight",
"//java/compiler:compiler-tests_test_lib",
"//java/testFramework",
"//xml/dom-tests:dom-tests_test_lib",
diff --git a/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml b/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml
index 6aa6683bbba8..e21aa938edad 100644
--- a/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml
+++ b/plugins/devkit/devkit-java-tests/intellij.devkit.java.tests.iml
@@ -33,6 +33,7 @@
+
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/WrongPluginModuleAliasInspectionTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/WrongPluginModuleAliasInspectionTest.kt
new file mode 100644
index 000000000000..a6e33107eafb
--- /dev/null
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/WrongPluginModuleAliasInspectionTest.kt
@@ -0,0 +1,104 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.devkit.inspections
+
+import com.intellij.ide.plugins.PluginManagerCore
+import com.intellij.openapi.project.IntelliJProjectUtil
+import com.intellij.openapi.project.Project
+import com.intellij.platform.testFramework.junit5.codeInsight.fixture.codeInsightFixture
+import com.intellij.testFramework.junit5.TestApplication
+import com.intellij.testFramework.junit5.fixture.TestFixture
+import com.intellij.testFramework.junit5.fixture.moduleFixture
+import com.intellij.testFramework.junit5.fixture.projectFixture
+import com.intellij.testFramework.junit5.fixture.tempPathFixture
+import org.intellij.lang.annotations.Language
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.MethodSource
+import java.nio.file.Path
+import java.util.stream.Stream
+import kotlin.streams.asStream
+
+@TestApplication
+class WrongPluginModuleAliasInspectionTest {
+
+ private val tempDir: TestFixture = tempPathFixture()
+ private val project: TestFixture = projectFixture(tempDir, openAfterCreation = true)
+
+ @Suppress("unused") // required by codeInsightFixture
+ private val module by project.moduleFixture(tempDir, addPathToSourceRoot = true)
+ private val fixture = codeInsightFixture(project, tempDir)
+
+ @BeforeEach
+ fun setUp() {
+ fixture.get().enableInspections(WrongPluginModuleAliasInspection())
+ }
+
+ @DisplayName("Plugin module alias inspection test")
+ @ParameterizedTest(name = "{0} when vendor is ''{1}'', module prefix is ''{2}'', and IntelliJ Platform project is {3}")
+ @MethodSource("testCases")
+ fun testPluginModuleAlias(
+ testExpectationPrefix: String,
+ vendor: String,
+ modulePrefix: String,
+ isIntelliJProject: Boolean,
+ ) {
+ if (isIntelliJProject) {
+ IntelliJProjectUtil.markAsIntelliJPlatformProject(project.get(), true)
+ }
+
+ val moduleValue = "${modulePrefix}myFeature"
+ val errorTag = if (testExpectationPrefix == ERROR_EXPECTED) {
+ """$moduleValue"""
+ }
+ else {
+ moduleValue
+ }
+
+ doTest("""
+
+ $vendor
+
+
+ """.trimIndent())
+ }
+
+ private fun doTest(@Language("XML") xml: String) {
+ fixture.get().apply {
+ configureByText("plugin.xml", xml)
+ testHighlighting(false, false, true)
+ }
+ }
+
+ companion object {
+ private const val ERROR_EXPECTED = "should report error"
+ private const val ERROR_NOT_EXPECTED = "should not report error"
+
+ @JvmStatic
+ fun testCases(): Stream =
+ cartesianProduct(
+ listOf("JetBrains", "JetBrains s.r.o.", "JetBrains, Google", "Acme"),
+ listOf("com.intellij.", "com.example."),
+ listOf(true, false)
+ ).map { (vendor, prefix, isIntelliJProject) ->
+ val expectError = !PluginManagerCore.isDevelopedByJetBrains(vendor) && prefix == "com.intellij." && !isIntelliJProject
+ val testExpectationPrefix = if (expectError) ERROR_EXPECTED else ERROR_NOT_EXPECTED
+ Arguments.of(testExpectationPrefix, vendor, prefix, isIntelliJProject)
+ }.asStream()
+
+ private fun cartesianProduct(
+ listA: List,
+ listB: List,
+ listC: List,
+ ): Sequence> = sequence {
+ for (a in listA) {
+ for (b in listB) {
+ for (c in listC) {
+ yield(Triple(a, b, c))
+ }
+ }
+ }
+ }
+ }
+}