diff --git a/Cabal/src/Distribution/Simple/Bench.hs b/Cabal/src/Distribution/Simple/Bench.hs
index c3b3802876fc27ca9b285a0f048569784114e4db..78f169f255afaabbcd873295bc4f7f5988c59eea 100644
--- a/Cabal/src/Distribution/Simple/Bench.hs
+++ b/Cabal/src/Distribution/Simple/Bench.hs
@@ -22,7 +22,6 @@ module Distribution.Simple.Bench
 import Distribution.Compat.Prelude
 import Prelude ()
 
-import Distribution.Compat.Environment
 import qualified Distribution.PackageDescription as PD
 import Distribution.Pretty
 import Distribution.Simple.Build (addInternalBuildTools)
@@ -89,15 +88,12 @@ bench args pkg_descr lbi flags = do
               dieWithException verbosity $
                 NoBenchMarkProgram cmd
 
-            existingEnv <- getEnvironment
-
             -- Compute the appropriate environment for running the benchmark
             let progDb = LBI.withPrograms lbiForBench
                 pathVar = progSearchPath progDb
                 envOverrides = progOverrideEnv progDb
             newPath <- programSearchPathAsPATHVar pathVar
-            overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides)
-            let shellEnv = overrideEnv ++ existingEnv
+            shellEnv <- getFullEnvironment ([("PATH", Just newPath)] ++ envOverrides)
 
             -- Add (DY)LD_LIBRARY_PATH if needed
             shellEnv' <-
diff --git a/Cabal/src/Distribution/Simple/Program/Run.hs b/Cabal/src/Distribution/Simple/Program/Run.hs
index 0a9ddb0e7b5d07fae7d731155fb4ee79f2a9cc29..a0e0346cb2c3b4aaac31ba5530c303ba5f2816ff 100644
--- a/Cabal/src/Distribution/Simple/Program/Run.hs
+++ b/Cabal/src/Distribution/Simple/Program/Run.hs
@@ -29,6 +29,7 @@ module Distribution.Simple.Program.Run
   , getProgramInvocationOutputAndErrors
   , getProgramInvocationLBSAndErrors
   , getEffectiveEnvironment
+  , getFullEnvironment
   ) where
 
 import Distribution.Compat.Prelude
@@ -237,6 +238,12 @@ getProgramInvocationIODataAndErrors
 -- | Return the current environment extended with the given overrides.
 -- If an entry is specified twice in @overrides@, the second entry takes
 -- precedence.
+--
+-- getEffectiveEnvironment returns 'Nothing' when there are no overrides.
+-- It returns an argument that is suitable to pass directly to 'CreateProcess' to
+-- override the environment.
+-- If you need the full environment to manipulate further, even when there are no overrides,
+-- then call 'getFullEnvironment'.
 getEffectiveEnvironment
   :: [(String, Maybe String)]
   -> IO (Maybe [(String, String)])
@@ -248,6 +255,17 @@ getEffectiveEnvironment overrides =
     update (var, Nothing) = Map.delete var
     update (var, Just val) = Map.insert var val
 
+-- | Like 'getEffectiveEnvironment', but when no overrides are specified,
+-- returns the full environment instead of 'Nothing'.
+getFullEnvironment
+  :: [(String, Maybe String)]
+  -> IO [(String, String)]
+getFullEnvironment overrides = do
+  menv <- getEffectiveEnvironment overrides
+  case menv of
+    Just env -> return env
+    Nothing -> getEnvironment
+
 -- | Like the unix xargs program. Useful for when we've got very long command
 -- lines that might overflow an OS limit on command line length and so you
 -- need to invoke a command multiple times to get all the args in.
diff --git a/Cabal/src/Distribution/Simple/Test/ExeV10.hs b/Cabal/src/Distribution/Simple/Test/ExeV10.hs
index 8e20efffe51b480b29d41d5f7fe5e1b3006d13c0..3ad112af2bbde0fdc5326b4f2a49f372c1a27262 100644
--- a/Cabal/src/Distribution/Simple/Test/ExeV10.hs
+++ b/Cabal/src/Distribution/Simple/Test/ExeV10.hs
@@ -8,7 +8,6 @@ module Distribution.Simple.Test.ExeV10
 import Distribution.Compat.Prelude
 import Prelude ()
 
-import Distribution.Compat.Environment
 import qualified Distribution.PackageDescription as PD
 import Distribution.Simple.BuildPaths
 import Distribution.Simple.Compiler
@@ -64,8 +63,6 @@ runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do
       way = guessWay lbi
       tixDir_ = i $ tixDir distPref way
 
-  existingEnv <- getEnvironment
-
   let cmd =
         i (LBI.buildDir lbi)
           </> testName'
@@ -92,13 +89,18 @@ runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do
       pathVar = progSearchPath progDb
       envOverrides = progOverrideEnv progDb
   newPath <- programSearchPathAsPATHVar pathVar
-  overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides)
   let opts =
         map
           (testOption pkg_descr lbi suite)
           (testOptions flags)
       tixFile = packageRoot (testCommonFlags flags) </> getSymbolicPath (tixFilePath distPref way (testName'))
-      shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled] ++ overrideEnv ++ existingEnv
+
+  shellEnv <-
+    getFullEnvironment
+      ( [("PATH", Just newPath)]
+          ++ [("HPCTIXFILE", Just tixFile) | isCoverageEnabled]
+          ++ envOverrides
+      )
 
   -- Add (DY)LD_LIBRARY_PATH if needed
   shellEnv' <-
diff --git a/Cabal/src/Distribution/Simple/Test/LibV09.hs b/Cabal/src/Distribution/Simple/Test/LibV09.hs
index 3807cc9ae9d40100bb798ad136583477bb2338b2..1d2de6f8a415a662257c3221e7c2b10f9f4e980e 100644
--- a/Cabal/src/Distribution/Simple/Test/LibV09.hs
+++ b/Cabal/src/Distribution/Simple/Test/LibV09.hs
@@ -17,7 +17,6 @@ import Distribution.Compat.Prelude
 import Distribution.Types.UnqualComponentName
 import Prelude ()
 
-import Distribution.Compat.Environment
 import Distribution.Compat.Internal.TempFile
 import Distribution.Compat.Process (proc)
 import Distribution.ModuleName
@@ -70,7 +69,6 @@ runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do
       way = guessWay lbi
 
   let mbWorkDir = LBI.mbWorkDirLBI lbi
-  existingEnv <- getEnvironment
 
   let cmd =
         interpretSymbolicPath mbWorkDir (LBI.buildDir lbi)
@@ -100,15 +98,17 @@ runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do
         pathVar = progSearchPath progDb
         envOverrides = progOverrideEnv progDb
     newPath <- programSearchPathAsPATHVar pathVar
-    overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides)
 
     -- Run test executable
     let opts = map (testOption pkg_descr lbi suite) $ testOptions flags
         tixFile = i $ tixFilePath distPref way testName'
-        shellEnv =
-          [("HPCTIXFILE", tixFile) | isCoverageEnabled]
-            ++ overrideEnv
-            ++ existingEnv
+
+    shellEnv <-
+      getFullEnvironment
+        ( [("PATH", Just newPath)]
+            ++ [("HPCTIXFILE", Just tixFile) | isCoverageEnabled]
+            ++ envOverrides
+        )
     -- Add (DY)LD_LIBRARY_PATH if needed
     shellEnv' <-
       if LBI.withDynExe lbi
diff --git a/cabal-install/src/Distribution/Client/Run.hs b/cabal-install/src/Distribution/Client/Run.hs
index 7ff4c8bb5e84e66c267021a1f0fa76013527e1c5..88671a9f53ccd0a1cf6c613eb6a7e0931d91e2a0 100644
--- a/cabal-install/src/Distribution/Client/Run.hs
+++ b/cabal-install/src/Distribution/Client/Run.hs
@@ -59,7 +59,6 @@ import Distribution.Types.UnqualComponentName
 import qualified Distribution.Simple.GHCJS as GHCJS
 
 import Distribution.Client.Errors
-import Distribution.Compat.Environment (getEnvironment)
 import Distribution.Utils.Path
 
 -- | Return the executable to run and any extra arguments that should be
@@ -178,13 +177,11 @@ run verbosity lbi exe exeArgs = do
             return (p, [])
 
   -- Compute the appropriate environment for running the executable
-  existingEnv <- getEnvironment
   let progDb = withPrograms lbiForExe
       pathVar = progSearchPath progDb
       envOverrides = progOverrideEnv progDb
   newPath <- programSearchPathAsPATHVar pathVar
-  overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides)
-  let env = overrideEnv ++ existingEnv
+  env <- getFullEnvironment ([("PATH", Just newPath)] ++ envOverrides)
 
   -- Add (DY)LD_LIBRARY_PATH if needed
   env' <-
diff --git a/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.out b/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.out
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.project b/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.project
new file mode 100644
index 0000000000000000000000000000000000000000..58d710ed2dd372f739b85af661956ea6702b2959
--- /dev/null
+++ b/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.project
@@ -0,0 +1 @@
+packages: p
diff --git a/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.test.hs b/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.test.hs
new file mode 100644
index 0000000000000000000000000000000000000000..f02f935010238577d9e057be98a2c4abe4b34223
--- /dev/null
+++ b/cabal-testsuite/PackageTests/DuplicateEnvVars/cabal.test.hs
@@ -0,0 +1,5 @@
+import Test.Cabal.Prelude
+
+main = cabalTest $ recordMode DoNotRecord $ do
+    res <- cabal' "test" ["all"]
+    assertOutputContains "No duplicate environment variables found" res
diff --git a/cabal-testsuite/PackageTests/DuplicateEnvVars/p/Main.hs b/cabal-testsuite/PackageTests/DuplicateEnvVars/p/Main.hs
new file mode 100644
index 0000000000000000000000000000000000000000..42bf24965539f11b6b7a45cc82d7956fc83ab77a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/DuplicateEnvVars/p/Main.hs
@@ -0,0 +1,16 @@
+module Main where
+
+import Data.List (group, sort)
+import System.Environment (getEnvironment)
+
+main = do
+    env <- getEnvironment
+    let sortedEnv = sort env
+        duplicates = filter (\g -> length g > 1) $ group $ map fst sortedEnv
+
+    if null duplicates
+        then putStrLn "No duplicate environment variables found."
+        else do
+            putStrLn "Found duplicate environment variables:"
+            mapM_ (\d -> putStrLn $ "  - " ++ head d) duplicates
+            fail "Test failed due to duplicate environment variables"
diff --git a/cabal-testsuite/PackageTests/DuplicateEnvVars/p/p.cabal b/cabal-testsuite/PackageTests/DuplicateEnvVars/p/p.cabal
new file mode 100644
index 0000000000000000000000000000000000000000..23bc3d599027336608677b5468b2a32532e155e4
--- /dev/null
+++ b/cabal-testsuite/PackageTests/DuplicateEnvVars/p/p.cabal
@@ -0,0 +1,10 @@
+cabal-version:      3.0
+name:               p
+version:            0.1.0.0
+build-type:         Simple
+
+test-suite env-test
+    default-language: Haskell2010
+    type:             exitcode-stdio-1.0
+    main-is:          Main.hs
+    build-depends:    base
diff --git a/changelog.d/pr-10827.md b/changelog.d/pr-10827.md
new file mode 100644
index 0000000000000000000000000000000000000000..9fb5b7b832883b4c4887bf129d419fc628f78044
--- /dev/null
+++ b/changelog.d/pr-10827.md
@@ -0,0 +1,11 @@
+---
+synopsis: "Fix duplicate environment variables in test and benchmark runs"
+packages: [Cabal, cabal-install]
+prs: 10827
+issues: 10718
+---
+
+Cabal no longer creates duplicate environment variables when running test
+suites, benchmarks, or internal executables. Previously, when setting up the
+environment for these processes, Cabal would append the overridden environment
+to the existing environment, creating duplicates of the same variable.