diff --git a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
index e15adcec74c6efaee85c11e388517683262c6522..58c40ebec78ecb3ab4585b9dc744392c4aa19042 100755
--- a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
@@ -56,6 +56,8 @@ atlas_add_component( FaserActsGeometry
                          src/FaserActsAlignmentCondAlg.cxx
                          src/NominalAlignmentCondAlg.cxx
                          src/FaserActsVolumeMappingTool.cxx
+                         src/FaserActsGeometryBoundaryTestAlg.h
+                         src/FaserActsGeometryBoundaryTestAlg.cxx
                          src/components/*.cxx
                          PUBLIC_HEADERS FaserActsGeometry
                          INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${BOOST_INCLUDE_DIRS}
@@ -84,3 +86,7 @@ atlas_install_headers( FaserActsGeometry )
 atlas_install_python_modules( python/*.py )
 atlas_install_scripts( test/*.py )
 
+atlas_add_test( FaserActsGeometryBoundary_test
+                SCRIPT python ${CMAKE_CURRENT_SOURCE_DIR}/test/FaserActsGeometryBoundary_test.py
+                PROPERTIES WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+                PROPERTIES TIMEOUT 300 )
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsGeometryBoundaryTestAlg.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsGeometryBoundaryTestAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..57c1e3a2fe68bea133d167ea00dd539edfc0f3fe
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsGeometryBoundaryTestAlg.cxx
@@ -0,0 +1,97 @@
+/*
+  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS and FASER collaborations
+*/
+
+
+#include "FaserActsGeometryBoundaryTestAlg.h"
+#include "FaserActsGeometry/FaserActsGeometryContext.h"
+#include "Acts/Surfaces/Surface.hpp"
+#include "Acts/Surfaces/PlaneSurface.hpp"
+#include "Acts/Surfaces/RectangleBounds.hpp"
+#include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/Geometry/DetectorElementBase.hpp"
+#include "Acts/Geometry/TrackingVolume.hpp"
+
+
+FaserActsGeometryBoundaryTestAlg::FaserActsGeometryBoundaryTestAlg(const std::string &name, ISvcLocator *pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator) {}
+
+
+StatusCode FaserActsGeometryBoundaryTestAlg::initialize() {
+  ATH_CHECK(m_trackingGeometryTool.retrieve());
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode FaserActsGeometryBoundaryTestAlg::execute(const EventContext &ctx) const {
+
+  std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry
+      = m_trackingGeometryTool->trackingGeometry();
+
+  const Acts::GeometryContext gctx =
+      m_trackingGeometryTool->getGeometryContext(ctx).context();
+
+  // loop over all tracking layer and check if contained detector elements are insie boundaries
+  // return StatusCode::Failure so that test fails, if the edge of any detector element is outside boundaries
+  const Acts::TrackingVolume *trackingVolume = trackingGeometry->highestTrackingVolume();
+  for (auto volume : trackingVolume->confinedVolumes()->arrayObjects()) {
+    for (const auto& layer : volume->confinedLayers()->arrayObjects()) {
+      if (layer->layerType() == Acts::LayerType::active) {
+        // get inner and outer boundaries from approach descriptor:
+        // - innerBoundary is approach suface with minimum z position
+        // - outerBoundary is approach suface with maximum z position
+        Acts::SurfaceVector approachSurfaces = layer->approachDescriptor()->containedSurfaces();
+        const Acts::Surface *innerApproachSurface = *std::min_element(
+            approachSurfaces.begin(), approachSurfaces.end(),
+            [&gctx](const auto &lhs, const auto &rhs) {
+                return lhs->center(gctx).z() < rhs->center(gctx).z();
+            }
+        );
+        const Acts::Surface *outerApproachSurface = *std::max_element(
+            approachSurfaces.begin(), approachSurfaces.end(),
+            [&gctx](const auto &lhs, const auto &rhs) {
+                return lhs->center(gctx).z() < rhs->center(gctx).z();
+            }
+        );
+        double zInnerBoundary = innerApproachSurface->center(gctx).z();
+        double zOuterBoundary = outerApproachSurface->center(gctx).z();
+
+        // loop over surface array and check if all edges are between inner and outer boundary
+        for (const Acts::Surface *surface : layer->surfaceArray()->surfaces()) {
+          auto planeSurface = dynamic_cast<const Acts::PlaneSurface *>(surface);
+          // make sure surface has a associated detector element (there are other active detector elements 
+          // e.g. containing material or at the tracking volume boundaries)
+          if (surface->associatedDetectorElement() != nullptr) {
+            auto bounds = dynamic_cast<const Acts::RectangleBounds*>(&surface->bounds());
+            const Acts::Vector2 min = bounds->min();
+            const Acts::Vector2 max = bounds->max();
+            // create dummpy momentum vector: local to global transformation requires  momentum vector,
+            // which is ignored for PlaneSurface
+            Acts::Vector3 dummyMomentum {1., 1., 1.};
+            // get global position at all edges of the surface
+            std::vector<Acts::Vector3> edges {};
+            edges.push_back(planeSurface->localToGlobal(gctx, {min.x(), min.y()}, dummyMomentum));
+            edges.push_back(planeSurface->localToGlobal(gctx, {min.x(), max.y()}, dummyMomentum));
+            edges.push_back(planeSurface->localToGlobal(gctx, {max.x(), min.y()}, dummyMomentum));
+            edges.push_back(planeSurface->localToGlobal(gctx, {max.x(), max.y()}, dummyMomentum));
+            for (const Acts::Vector3 &edgePosition : edges) {
+              if ((edgePosition.z() < zInnerBoundary) || (edgePosition.z() > zOuterBoundary)) {
+                std::cout << "?? surface outside boundaries\n";
+                std::cout << "inner Boundary: " << zInnerBoundary << std::endl;
+                std::cout << "outer Boundary: " << zOuterBoundary << std::endl;
+                std::cout << "edge: " << edgePosition.x() << ", " << edgePosition.y() << ", " << edgePosition.z() << std::endl;
+                return StatusCode::FAILURE;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode FaserActsGeometryBoundaryTestAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsGeometryBoundaryTestAlg.h b/Tracking/Acts/FaserActsGeometry/src/FaserActsGeometryBoundaryTestAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..b2c0bf3c73b35ac1d0b9857a8c0aae72cfb3c56c
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsGeometryBoundaryTestAlg.h
@@ -0,0 +1,25 @@
+/*
+  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS and FASER collaborations
+*/
+
+#ifndef FASERACTSGEOMETRY_FASERACTSGEOMETRYBOUNDARYTESTALG_H
+#define FASERACTSGEOMETRY_FASERACTSGEOMETRYBOUNDARYTESTALG_H
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+
+
+class FaserActsGeometryBoundaryTestAlg : public AthReentrantAlgorithm {
+public:
+  FaserActsGeometryBoundaryTestAlg(const std::string &name, ISvcLocator *pSvcLocator);
+  virtual StatusCode initialize() override final;
+  virtual StatusCode execute(const EventContext &ctx) const override final;
+  virtual StatusCode finalize() override final;
+
+private:
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {
+    this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
+};
+
+
+#endif // FASERACTSGEOMETRY_FASERACTSGEOMETRYBOUNDARYTESTALG_H
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx b/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx
index e7b7fb2fe49208911b0d98c2ba4a6d6b960df89f..a103c7a9466eb66446036cc2978e82dba8889fee 100755
--- a/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx
+++ b/Tracking/Acts/FaserActsGeometry/src/components/FaserActsGeometry_entries.cxx
@@ -16,6 +16,7 @@
 #include "../FaserActsMaterialMapping.h"
 #include "../FaserActsSurfaceMappingTool.h"
 #include "../FaserActsMaterialTrackWriterSvc.h"
+#include "../FaserActsGeometryBoundaryTestAlg.h"
 
 DECLARE_COMPONENT( FaserActsTrackingGeometrySvc )
 DECLARE_COMPONENT( FaserActsTrackingGeometryTool )
@@ -30,3 +31,4 @@ DECLARE_COMPONENT( FaserActsMaterialJsonWriterTool )
 DECLARE_COMPONENT( FaserActsMaterialTrackWriterSvc )
 DECLARE_COMPONENT( FaserActsMaterialMapping )
 DECLARE_COMPONENT( FaserActsSurfaceMappingTool )
+DECLARE_COMPONENT( FaserActsGeometryBoundaryTestAlg )
diff --git a/Tracking/Acts/FaserActsGeometry/test/FaserActsGeometryBoundary_test.py b/Tracking/Acts/FaserActsGeometry/test/FaserActsGeometryBoundary_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6a841642b17b6ecd412fc55ced498524ece9ca5
--- /dev/null
+++ b/Tracking/Acts/FaserActsGeometry/test/FaserActsGeometryBoundary_test.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+"""
+Copyright (C) 2002-2023 CERN for the benefit of the ATLAS and FASER collaboration
+"""
+
+
+def FaserActsGeometryBoundaryTestCfg(flags, name="FaserActsGeometryBoundaryTestAlg", **kwargs):
+
+    from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+    from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
+    from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometryToolCfg
+    from AthenaConfiguration.ComponentFactory import CompFactory
+
+    acc = FaserSCT_GeometryCfg(flags)
+    acc.merge(MagneticFieldSvcCfg(flags))
+    result, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(flags)
+    test_alg = CompFactory.FaserActsGeometryBoundaryTestAlg
+    test_alg.TrackingGeometryTool = actsTrackingGeometryTool
+    acc.merge(result)
+    acc.addEventAlgo(test_alg(name, **kwargs))
+    return acc
+
+
+if __name__ == "__main__":
+    
+    import sys
+    from AthenaCommon.Configurable import Configurable
+    from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+    from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+    from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+
+    Configurable.configurableRun3Behavior = True
+    ConfigFlags.Input.isMC = False
+    ConfigFlags.GeoModel.Align.Dynamic = False
+    ConfigFlags.IOVDb.DatabaseInstance = "CONDBR3"
+    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-04"
+    ConfigFlags.GeoModel.FaserVersion = "FASERNU-03"
+    ConfigFlags.Detector.GeometryFaserSCT = True
+    ConfigFlags.lock()
+
+    acc = MainServicesCfg(ConfigFlags)
+    acc.merge(FaserGeometryCfg(ConfigFlags))
+    acc.merge(FaserActsGeometryBoundaryTestCfg(ConfigFlags))
+
+    replicaSvc = acc.getService("DBReplicaSvc")
+    replicaSvc.COOLSQLiteVetoPattern = ""
+    replicaSvc.UseCOOLSQLite = True
+    replicaSvc.UseCOOLFrontier = False
+    replicaSvc.UseGeomSQLite = True
+
+    sys.exit(int(acc.run(maxEvents=1).isFailure()))