diff --git a/Cabal/src/Distribution/PackageDescription/Check/Paths.hs b/Cabal/src/Distribution/PackageDescription/Check/Paths.hs
index 5b2df1f18fa95ca9c7443f63f63bf70192904571..28e1e3815e2f41d7586a13fbadf8e9a4a7259361 100644
--- a/Cabal/src/Distribution/PackageDescription/Check/Paths.hs
+++ b/Cabal/src/Distribution/PackageDescription/Check/Paths.hs
@@ -10,6 +10,7 @@
 module Distribution.PackageDescription.Check.Paths
   ( checkGlob
   , checkPath
+  , checkPackageFileNamesWithGlob
   , fileExtensionSupportedLanguage
   , isGoodRelativeDirectoryPath
   , isGoodRelativeFilePath
diff --git a/Cabal/src/Distribution/PackageDescription/Check/Target.hs b/Cabal/src/Distribution/PackageDescription/Check/Target.hs
index 0bf173cb980b54f84822ba76e815c17c2063150b..9e23b0af91742b7147c4202c4ec63ad662532c30 100644
--- a/Cabal/src/Distribution/PackageDescription/Check/Target.hs
+++ b/Cabal/src/Distribution/PackageDescription/Check/Target.hs
@@ -21,7 +21,7 @@ import Prelude ()
 import Distribution.CabalSpecVersion
 import Distribution.Compat.Lens
 import Distribution.Compiler
-import Distribution.ModuleName (ModuleName)
+import Distribution.ModuleName (ModuleName, toFilePath)
 import Distribution.Package
 import Distribution.PackageDescription
 import Distribution.PackageDescription.Check.Common
@@ -61,6 +61,8 @@ checkLibrary
           _libVisibility_
           libBuildInfo_
         ) = do
+    mapM_ checkModuleName (explicitLibModules lib)
+
     checkP
       (libName_ == LMainLibName && isSub)
       (PackageBuildImpossible UnnamedInternal)
@@ -144,6 +146,8 @@ checkExecutable
     let cet = CETExecutable exeName_
         modulePath_ = getSymbolicPath symbolicModulePath_
 
+    mapM_ checkModuleName (exeModules exe)
+
     -- § Exe specific checks
     checkP
       (null modulePath_)
@@ -205,6 +209,9 @@ checkTestSuite
       TestSuiteUnsupported tt ->
         tellP (PackageBuildWarning $ TestsuiteNotSupported tt)
       _ -> return ()
+
+    mapM_ checkModuleName (testModules ts)
+
     checkP
       mainIsWrongExt
       (PackageBuildImpossible NoHsLhsMain)
@@ -257,6 +264,8 @@ checkBenchmark
     -- Target type/name (benchmark).
     let cet = CETBenchmark benchmarkName_
 
+    mapM_ checkModuleName (benchmarkModules bm)
+
     -- § Interface & bm specific tests.
     case benchmarkInterface_ of
       BenchmarkUnsupported tt@(BenchmarkTypeUnknown _ _) ->
@@ -294,6 +303,11 @@ checkBenchmark
           BenchmarkExeV10 _ f -> takeExtension (getSymbolicPath f) `notElem` [".hs", ".lhs"]
           _ -> False
 
+-- | Check if a module name is valid on both Windows and Posix systems
+checkModuleName :: Monad m => ModuleName -> CheckM m ()
+checkModuleName moduleName =
+  checkPackageFileNamesWithGlob PathKindFile (toFilePath moduleName)
+
 -- ------------------------------------------------------------
 -- Build info
 -- ------------------------------------------------------------
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/InvalidModuleName.cabal b/cabal-testsuite/PackageTests/Check/InvalidModuleName/InvalidModuleName.cabal
new file mode 100644
index 0000000000000000000000000000000000000000..e298eece9b6efd71b7b91a42e5b4f6bccb33adad
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Check/InvalidModuleName/InvalidModuleName.cabal
@@ -0,0 +1,44 @@
+name:                InvalidModuleName
+version:             0.1.0.0
+license:             BSD3
+license-file:        LICENSE
+category:            development
+author:              Foo Bar
+maintainer:          cabal-dev@haskell.org
+build-type:          Simple
+cabal-version:       >=1.10
+synopsis:            Test for invalid module names
+description:         Tests that invalid module names are properly rejected by cabal check
+
+library
+  exposed-modules:     Aux
+  build-depends:       base < 5
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+
+executable invalid-exe
+  main-is:             Main.hs
+  other-modules:       Exe.Aux
+                     , Exe.Aux.Test
+  build-depends:       base < 5
+  hs-source-dirs:      exe
+  default-language:    Haskell2010
+
+test-suite invalid-test
+  type:                exitcode-stdio-1.0
+  main-is:             Main.hs
+  other-modules:       Test.Aux
+                     , Test.Aux.Test
+  build-depends:       base < 5
+  hs-source-dirs:      test
+  default-language:    Haskell2010
+
+benchmark invalid-bench
+  type:                exitcode-stdio-1.0
+  main-is:             Main.hs
+  other-modules:       Bench.Aux
+                     , Bench.Aux.Test
+  build-depends:       base < 5
+  hs-source-dirs:      bench
+  default-language:    Haskell2010
+
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/LICENSE b/cabal-testsuite/PackageTests/Check/InvalidModuleName/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/bench/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/bench/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.out b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.out
new file mode 100644
index 0000000000000000000000000000000000000000..3093fce3d24086ca5d44db03730ac43864fc51ca
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.out
@@ -0,0 +1,10 @@
+# cabal check
+The following errors will cause portability problems on other environments:
+Error: [invalid-path-win] The path 'Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Bench/Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Bench/Aux/Test' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Exe/Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Exe/Aux/Test' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Test/Aux' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: [invalid-path-win] The path 'Test/Aux/Test' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|", and there are a few reserved names including "aux", "nul", "con", "prn", "com{1-9}", "lpt{1-9}" and "clock$".
+Error: Hackage would reject this package.
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.test.hs b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.test.hs
new file mode 100644
index 0000000000000000000000000000000000000000..8756cdecc852fd4234b6fd0efbb74faca0c54983
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Check/InvalidModuleName/cabal.test.hs
@@ -0,0 +1,5 @@
+import Test.Cabal.Prelude
+
+main = cabalTest $
+    fails $ cabal "check" []
+
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/exe/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/exe/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/src/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/src/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/Check/InvalidModuleName/test/.file b/cabal-testsuite/PackageTests/Check/InvalidModuleName/test/.file
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/changelog.d/pr-10816.md b/changelog.d/pr-10816.md
new file mode 100644
index 0000000000000000000000000000000000000000..06118ecbb5b08477890131427cc00e9ca4bcc70a
--- /dev/null
+++ b/changelog.d/pr-10816.md
@@ -0,0 +1,23 @@
+synopsis: "Add checks for Windows reserved filenames in module paths"
+packages: Cabal cabal-install
+prs: #10816
+issues: #10295
+
+description: {
+
+On Windows, certain filenames are reserved by the operating system such as
+"aux", "con", "prn", "nul", etc. When these names appear in module paths they
+can cause build failures on Windows systems.
+
+`cabal check` now properly warns about module paths that contain Windows reserved
+filenames, not just filepaths which contain these reserved tokens. These warnings
+are controlled by the existing `invalid-win-path` category.
+
+For example, module paths like:
+- `Exe.Aux.Test`
+- `Test.Aux.Module`
+- `Bench.Aux.Helpers`
+
+will now trigger appropriate warnings during `cabal check`.
+
+}