diff --git a/typo3/sysext/extbase/Classes/Core/Bootstrap.php b/typo3/sysext/extbase/Classes/Core/Bootstrap.php
index 33646b0d4a3f41ab248e5ba352a732c4b3397d85..13674d3e8fd39a82d0c95f50dafaae7048c031f4 100644
--- a/typo3/sysext/extbase/Classes/Core/Bootstrap.php
+++ b/typo3/sysext/extbase/Classes/Core/Bootstrap.php
@@ -109,9 +109,8 @@ class Bootstrap
     {
         if ($this->cObj === null) {
             $this->cObj = $this->container->get(ContentObjectRenderer::class);
-            $request = $request->withAttribute('currentContentObject', $this->cObj);
+            $this->cObj->setRequest($request);
         }
-        $this->cObj->setRequest($request);
         // @deprecated since v12. Remove in v13.
         $this->configurationManager->setContentObject($this->cObj);
         if (method_exists($this->configurationManager, 'setRequest')) {
diff --git a/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php b/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php
index f680831ef5e36e9fd2a0dc2a787907107bac394b..29b78404708be846700223b9689b8424e9203540 100644
--- a/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php
+++ b/typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php
@@ -696,7 +696,7 @@ class UriBuilder
             E_USER_DEPRECATED
         );
 
-        return ($contentObject = $this->getRequest()?->getArgument('currentContentObject')) instanceof ContentObjectRenderer
+        return ($contentObject = $this->getRequest()?->getAttribute('currentContentObject')) instanceof ContentObjectRenderer
             ? $contentObject
             : GeneralUtility::makeInstance(ContentObjectRenderer::class);
     }
diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php
index 4e3e2bb4a7eb030126c90c44efe0689b7dcdd9ba..ea28f0d16f2a3bc65fcb864287397626abf80535 100644
--- a/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php
+++ b/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php
@@ -128,7 +128,7 @@ final class CObjectViewHelper extends AbstractViewHelper
         /** @var RenderingContext $renderingContext */
         $request = $renderingContext->getRequest();
         $contentObjectRenderer = self::getContentObjectRenderer($request);
-        $contentObjectRenderer->setRequest($request->withAttribute('currentContentObject', $contentObjectRenderer));
+        $contentObjectRenderer->setRequest($request);
         $tsfeBackup = null;
         if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
             $tsfeBackup = self::simulateFrontendEnvironment();
@@ -216,7 +216,12 @@ final class CObjectViewHelper extends AbstractViewHelper
                 GeneralUtility::makeInstance(FrontendUserAuthentication::class)
             );
         }
-        return GeneralUtility::makeInstance(ContentObjectRenderer::class, $tsfe);
+        $contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class, $tsfe);
+        $parent = $request->getAttribute('currentContentObject');
+        if ($parent instanceof ContentObjectRenderer) {
+            $contentObjectRenderer->setParent($parent->data, $parent->currentRecord);
+        }
+        return $contentObjectRenderer;
     }
 
     /**
diff --git a/typo3/sysext/frontend/Classes/ContentObject/AbstractContentObject.php b/typo3/sysext/frontend/Classes/ContentObject/AbstractContentObject.php
index 1461f53e1a2628c9d5423671cbf7657fe0e26fa9..fe9c4c41da618ab60ea78345a389281cd6319b01 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/AbstractContentObject.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/AbstractContentObject.php
@@ -59,6 +59,11 @@ abstract class AbstractContentObject
     public function setContentObjectRenderer(ContentObjectRenderer $cObj): void
     {
         $this->cObj = $cObj;
+        // Provide the ContentObjectRenderer to the request as well, for code
+        // that only passes the request to more underlying layers, like Extbase does.
+        // Also makes sure the request in a Fluid RenderingContext also has the current
+        // content object available.
+        $this->request = $this->request->withAttribute('currentContentObject', $cObj);
     }
 
     protected function hasTypoScriptFrontendController(): bool
diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
index 822d110e7d4273659d7b9b05eaa649bbd0b17b96..55fb2b9da7b0aff0b8f6acb3c58ab793039955fe 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
@@ -4732,7 +4732,7 @@ class ContentObjectRenderer implements LoggerAwareInterface
                     if (method_exists($classObj, 'setContentObjectRenderer') && is_callable([$classObj, 'setContentObjectRenderer'])) {
                         $classObj->setContentObjectRenderer($this);
                     }
-                    $content = $callable($content, $conf, $this->getRequest());
+                    $content = $callable($content, $conf, $this->getRequest()->withAttribute('currentContentObject', $this));
                 } else {
                     $this->getTimeTracker()->setTSlogMessage('Method "' . $parts[1] . '" did not exist in class "' . $parts[0] . '"', LogLevel::ERROR);
                 }
@@ -4740,7 +4740,7 @@ class ContentObjectRenderer implements LoggerAwareInterface
                 $this->getTimeTracker()->setTSlogMessage('Class "' . $parts[0] . '" did not exist', LogLevel::ERROR);
             }
         } elseif (function_exists($funcName)) {
-            $content = $funcName($content, $conf);
+            $content = $funcName($content, $conf, $this->getRequest()->withAttribute('currentContentObject', $this));
         } else {
             $this->getTimeTracker()->setTSlogMessage('Function "' . $funcName . '" did not exist', LogLevel::ERROR);
         }
@@ -5869,35 +5869,32 @@ class ContentObjectRenderer implements LoggerAwareInterface
     }
 
     /**
-     * @todo: This getRequest() handling is pretty messy. We created a loop from
-     *        request to 'currentContentObject' back to request with this.
-     *        v13 should be refactored, probably with this patch chain:
-     *        * Remove fallback to $GLOBALS['TYPO3_REQUEST'] to force consumers
-     *          actually setting the request using setRequest().
-     *        * Protect this method.
-     *        * Get rid of public TSFE->cObj (the "page" instance of cObj).
-     *        * Avoid TSFE as constructor argument and make ContentObjectRenderer
-     *          free for DI, for instance to get the container injected.
-     *        * When getRequest() is protected or private, setRequest() should
-     *          *remove* the currentContentObject attribute again, to prevent
-     *          the object loop. This will work, since local getRequest() could
-     *          use $this when needed.
+     * @todo: This getRequest() is still a bit messy.
+     *        Underling code depends on both, a ContentObjectRenderer instance and a request,
+     *        but the API currently only passes one or the other. For instance Extbase and Fluid
+     *        only pass the Request, DataProcessors only a ContentObjectRenderer.
+     *        This is why getRequest() is currently public here.
+     *        A potential refactoring could:
+     *        * Create interfaces to pass both where needed (or pass a combined context object)
+     *        * Deprecate access to getRequest() here afterwards
+     *        A circular dependency that the instance of ContentObjectRenderer holds a
+     *        request with the instance of itself as attribute must be avoided.
+     *        This is currently achieved by adding a new request with
+     *        $this->request->withAttribute('currentContentObject', $cObj) in code that needs
+     *        it, but this new request is NOT passed back into the ContentObjectRenderer instance.
      *
-     * @internal This method will be set to protected with TYPO3 v13.
+     * @internal This method might be deprecated with TYPO3 v13.
      */
     public function getRequest(): ServerRequestInterface
     {
         if ($this->request instanceof ServerRequestInterface) {
-            // Note attribute 'currentContentObject' has been set by setRequest() already.
             return $this->request;
         }
-
         if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface) {
             // @todo: We may want to deprecate this fallback and force consumers
             //        to setRequest() after object instantiation / unserialization instead.
-            return $GLOBALS['TYPO3_REQUEST']->withAttribute('currentContentObject', $this);
+            return $GLOBALS['TYPO3_REQUEST'];
         }
-
         throw new ContentRenderingException(
             'PSR-7 request is missing in ContentObjectRenderer. Inject with start(), setRequest() or provide via $GLOBALS[\'TYPO3_REQUEST\'].',
             1607172972
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index 725539a63d980be65b26d01cb99da841746f871e..f0b0c6fdc2c65bbe57a28a78e1117303a2a91c56 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -2280,7 +2280,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
                     $nonCacheableContent = '';
                     $contentObjectRendererForNonCacheable = unserialize($nonCacheableData[$nonCacheableKey]['cObj']);
                     if ($contentObjectRendererForNonCacheable instanceof ContentObjectRenderer) {
-                        $contentObjectRendererForNonCacheable->setRequest($request->withAttribute('currentContentObject', $contentObjectRendererForNonCacheable));
+                        $contentObjectRendererForNonCacheable->setRequest($request);
                         $nonCacheableContent = match ($nonCacheableData[$nonCacheableKey]['type']) {
                             'COA' => $contentObjectRendererForNonCacheable->cObjGetSingle('COA', $nonCacheableData[$nonCacheableKey]['conf']),
                             'FUNC' => $contentObjectRendererForNonCacheable->cObjGetSingle('USER', $nonCacheableData[$nonCacheableKey]['conf']),
diff --git a/typo3/sysext/frontend/Classes/DataProcessing/FlexFormProcessor.php b/typo3/sysext/frontend/Classes/DataProcessing/FlexFormProcessor.php
index f9082c60373d8f0a17c4ad5a571df2cf3251ee8a..a508fe82f4369a6dcb912e47898fc488c3e82ee2 100644
--- a/typo3/sysext/frontend/Classes/DataProcessing/FlexFormProcessor.php
+++ b/typo3/sysext/frontend/Classes/DataProcessing/FlexFormProcessor.php
@@ -96,7 +96,7 @@ class FlexFormProcessor implements DataProcessorInterface
     protected function processAdditionalDataProcessors(array $data, array $processorConfiguration, ServerRequestInterface $request): array
     {
         $contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
-        $contentObjectRenderer->setRequest($request->withAttribute('currentContentObject', $contentObjectRenderer));
+        $contentObjectRenderer->setRequest($request);
         $contentObjectRenderer->start([$data], '');
         return GeneralUtility::makeInstance(ContentDataProcessor::class)->process(
             $contentObjectRenderer,
diff --git a/typo3/sysext/frontend/Tests/Unit/ContentObject/CaseContentObjectTest.php b/typo3/sysext/frontend/Tests/Unit/ContentObject/CaseContentObjectTest.php
index 95b64783ef1362b6ad35f11926195905911242ba..237b1b9cb2227fabf49e1482a5d2bac6b8196799 100644
--- a/typo3/sysext/frontend/Tests/Unit/ContentObject/CaseContentObjectTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/ContentObject/CaseContentObjectTest.php
@@ -43,7 +43,6 @@ final class CaseContentObjectTest extends UnitTestCase
 
         $request = new ServerRequest();
         $contentObjectRenderer = new ContentObjectRenderer($tsfe);
-        $request = $request->withAttribute('currentContentObject', $contentObjectRenderer);
         $contentObjectRenderer->setRequest($request);
         $cObjectFactoryMock = $this->getMockBuilder(ContentObjectFactory::class)->disableOriginalConstructor()->getMock();
 
@@ -64,6 +63,7 @@ final class CaseContentObjectTest extends UnitTestCase
         GeneralUtility::setContainer($container);
 
         $this->subject = new CaseContentObject();
+        $this->subject->setRequest($request);
         $this->subject->setContentObjectRenderer($contentObjectRenderer);
     }
 
diff --git a/typo3/sysext/frontend/Tests/Unit/ContentObject/ImageContentObjectTest.php b/typo3/sysext/frontend/Tests/Unit/ContentObject/ImageContentObjectTest.php
index 8d220809051d31938e4e455736a55f8875136eae..de5f807ee41895b50e4fe495c4442ea228fe43b3 100644
--- a/typo3/sysext/frontend/Tests/Unit/ContentObject/ImageContentObjectTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/ContentObject/ImageContentObjectTest.php
@@ -19,6 +19,7 @@ namespace TYPO3\CMS\Frontend\Tests\Unit\ContentObject;
 
 use PHPUnit\Framework\MockObject\MockObject;
 use TYPO3\CMS\Core\Cache\Frontend\NullFrontend;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
@@ -50,6 +51,7 @@ final class ImageContentObjectTest extends UnitTestCase
                 new NullFrontend('runtime'),
             ),
         ]);
+        $this->subject->setRequest(new ServerRequest());
         $this->subject->setContentObjectRenderer($contentObjectRenderer);
         $pageRenderer = $this->getMockBuilder(PageRenderer::class)->disableOriginalConstructor()->addMethods(['dummy'])->getMock();
         $this->subject->_set('pageRenderer', $pageRenderer);
@@ -381,6 +383,7 @@ final class ImageContentObjectTest extends UnitTestCase
             ),
         ]);
         $subject->_set('pageRenderer', $pageRenderer);
+        $subject->setRequest(new ServerRequest());
         $subject->setContentObjectRenderer($cObj);
         $result = $subject->_call('getImageSourceCollection', $layoutKey, $configuration, $file);
 
diff --git a/typo3/sysext/frontend/Tests/Unit/DataProcessing/FlexFormProcessorTest.php b/typo3/sysext/frontend/Tests/Unit/DataProcessing/FlexFormProcessorTest.php
index 6763db6861a67d6837d2dbc69893142c85db9ea1..0c1f75771bb032815e789f59edbfdae6571b4198 100644
--- a/typo3/sysext/frontend/Tests/Unit/DataProcessing/FlexFormProcessorTest.php
+++ b/typo3/sysext/frontend/Tests/Unit/DataProcessing/FlexFormProcessorTest.php
@@ -18,7 +18,6 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Frontend\Tests\Unit\DataProcessing;
 
 use PHPUnit\Framework\MockObject\MockObject;
-use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Service\FlexFormService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor;
@@ -205,9 +204,6 @@ final class FlexFormProcessorTest extends UnitTestCase
             ],
         ];
         $this->contentObjectRendererMock->expects(self::once())->method('start')->with([$convertedFlexFormData]);
-        $request = new ServerRequest();
-        $request = $request->withAttribute('currentContentObject', $this->contentObjectRendererMock);
-        $this->contentObjectRendererMock->method('getRequest')->willReturn($request);
 
         $contentDataProcessorMock = $this->getMockBuilder(ContentDataProcessor::class)->disableOriginalConstructor()->getMock();
         $renderedDataFromProcessors = [