diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-84214-AddCheckIfFieldsAreEditableForLinkvalidator.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-84214-AddCheckIfFieldsAreEditableForLinkvalidator.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b8386ce16e974949e7e88cd91fce7ae576c19ce7
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-84214-AddCheckIfFieldsAreEditableForLinkvalidator.rst
@@ -0,0 +1,42 @@
+.. include:: ../../Includes.txt
+
+====================================================================
+Feature: #84214 - Add check if fields are editable for Linkvalidator
+====================================================================
+
+See :issue:`84214`
+
+Description
+===========
+
+Broken links should only be shown in the list of broken links,
+if current backend user has edit access to the field. This way
+the editor will no longer get an error message on trying to
+edit records he has no permission to edit.
+
+Whether the editor has access depends on a number of factors.
+
+We check the following:
+
+* The current permissions of the page. For editing the page, the editor must have Permission::PAGE_EDIT, for editing content Permission::CONTENT_EDIT must be available
+* The user has write access to the table. We check if the table
+  is in 'tables_modify' for the group(s)
+* The user has write access to the field. We check if the field
+  is an exclude field. If yes, it must be included in
+  'non_exclude_fields' for the group(s).
+* The user has write permission for the language of the record
+* For tt_content: The CType is in list of explicitly allowed
+  values for authMode.
+
+Impact
+======
+
+* Broken links for fields that are not editable for the current backend
+  user will no longer be shown.
+* Fields were added to the tx_linkvalidator_link table. "Analyze
+  Database Structure" must be executed.
+* After an update to the new version, checking of broken links should
+  be reinitiated for the entire site. Until this is done, some broken
+  links may not be displayed for editors in the broken link report.
+
+.. index:: Backend, ext:linkvalidator
diff --git a/typo3/sysext/linkvalidator/Classes/LinkAnalyzer.php b/typo3/sysext/linkvalidator/Classes/LinkAnalyzer.php
index 90c7ac12c26973cc94f5b4fe014015d882e10235..7d368915512c744f66d3cd9b1cb30697cf111258 100644
--- a/typo3/sysext/linkvalidator/Classes/LinkAnalyzer.php
+++ b/typo3/sysext/linkvalidator/Classes/LinkAnalyzer.php
@@ -158,6 +158,12 @@ class LinkAnalyzer
 
             // Re-init selectFields for table
             $selectFields = array_merge(['uid', 'pid', $GLOBALS['TCA'][$table]['ctrl']['label']], $fields);
+            if ($GLOBALS['TCA'][$table]['ctrl']['languageField'] ?? false) {
+                $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
+            }
+            if ($GLOBALS['TCA'][$table]['ctrl']['type'] ?? false) {
+                $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['type'];
+            }
 
             $result = $queryBuilder->select(...$selectFields)
                 ->from($table)
@@ -196,6 +202,16 @@ class LinkAnalyzer
                 $record['link_title'] = $entryValue['link_title'];
                 $record['field'] = $entryValue['field'];
                 $record['last_check'] = time();
+                $typeField = $GLOBALS['TCA'][$table]['ctrl']['type'] ?? false;
+                if ($entryValue['row'][$typeField] ?? false) {
+                    $record['element_type'] = $entryValue['row'][$typeField];
+                }
+                $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField'] ?? false;
+                if ($languageField && isset($entryValue['row'][$languageField])) {
+                    $record['language'] = $entryValue['row'][$languageField];
+                } else {
+                    $record['language'] = -1;
+                }
                 $this->recordReference = $entryValue['substr']['recordRef'];
                 if (!empty($entryValue['pageAndAnchor'] ?? '')) {
                     // Page with anchor, e.g. 18#1580
@@ -462,13 +478,7 @@ class LinkAnalyzer
      */
     public function getLinkCounts()
     {
-        $groupedResult = $this->brokenLinkRepository->getNumberOfBrokenLinksForRecordsOnPages($this->pids);
-        $data = [];
-        foreach ($groupedResult as $linkType => $amount) {
-            $data[$linkType] = $amount;
-            $data['brokenlinkCount'] += $amount;
-        }
-        return $data;
+        return $this->brokenLinkRepository->getNumberOfBrokenLinksForRecordsOnPages($this->pids, $this->searchFields);
     }
 
     /**
diff --git a/typo3/sysext/linkvalidator/Classes/Linktype/InternalLinktype.php b/typo3/sysext/linkvalidator/Classes/Linktype/InternalLinktype.php
index 4708aaae57f06b24f15239f657cd9bc61c6b23fc..e438979edc739979a76f8ceaed506df60f466666 100644
--- a/typo3/sysext/linkvalidator/Classes/Linktype/InternalLinktype.php
+++ b/typo3/sysext/linkvalidator/Classes/Linktype/InternalLinktype.php
@@ -105,8 +105,8 @@ class InternalLinktype extends AbstractLinktype
             $this->responseContent = $this->checkContent($page, $anchor);
         }
         if (
-            is_array($this->errorParams['page']) && !$this->responsePage
-            || is_array($this->errorParams['content']) && !$this->responseContent
+            (is_array($this->errorParams['page']) && !$this->responsePage)
+            || (is_array($this->errorParams['content']) && !$this->responseContent)
         ) {
             $this->setErrorParams($this->errorParams);
         }
diff --git a/typo3/sysext/linkvalidator/Classes/QueryRestrictions/EditableRestriction.php b/typo3/sysext/linkvalidator/Classes/QueryRestrictions/EditableRestriction.php
new file mode 100644
index 0000000000000000000000000000000000000000..9d6a6d1138a9cfa2d513aa52dd7b9006c15e421d
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Classes/QueryRestrictions/EditableRestriction.php
@@ -0,0 +1,231 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Linkvalidator\QueryRestrictions;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Database\Connection;
+use TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression;
+use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
+use TYPO3\CMS\Core\Database\Query\QueryBuilder;
+use TYPO3\CMS\Core\Database\Query\QueryHelper;
+use TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionInterface;
+use TYPO3\CMS\Core\Type\Bitmask\Permission;
+
+class EditableRestriction implements QueryRestrictionInterface
+{
+    /**
+     * Specify which database fields the current user is allowed to edit
+     *
+     * @var array
+     */
+    protected $allowedFields = [];
+
+    /**
+     * Specify which languages the current user is allowed to edit
+     *
+     * @var array
+     */
+    protected $allowedLanguages = [];
+
+    /**
+     * Explicit allow fields
+     *
+     * @var array
+     */
+    protected $explicitAllowFields = [];
+
+    /**
+     * @var QueryBuilder
+     */
+    protected $queryBuilder;
+
+    /**
+     * @param array $searchFields array of 'table' => 'field1, field2'
+     *   in which linkvalidator searches for broken links.
+     * @param QueryBuilder $queryBuilder
+     */
+    public function __construct(array $searchFields, QueryBuilder $queryBuilder)
+    {
+        $this->allowedFields = $this->getAllowedFieldsForCurrentUser($searchFields);
+        $this->allowedLanguages = $this->getAllowedLanguagesForCurrentUser();
+        foreach ($searchFields as $table => $fields) {
+            if ($table !== 'pages' && ($GLOBALS['TCA'][$table]['ctrl']['type'] ?? false)) {
+                $type = $GLOBALS['TCA'][$table]['ctrl']['type'];
+                $this->explicitAllowFields[$table][$type] = $this->getExplicitAllowFieldsForCurrentUser($table, $type);
+            }
+        }
+        $this->queryBuilder = $queryBuilder;
+    }
+
+    /**
+     * Gets all allowed language ids for current backend user
+     *
+     * @return array
+     */
+    protected function getAllowedLanguagesForCurrentUser(): array
+    {
+        if (!(is_string($GLOBALS['BE_USER']->groupData['allowed_languages'] ?? false))) {
+            return [];
+        }
+
+        return array_map('intval', explode(',', $GLOBALS['BE_USER']->groupData['allowed_languages']));
+    }
+
+    protected function getExplicitAllowFieldsForCurrentUser(string $table, string $field): array
+    {
+        $allowDenyOptions = [];
+        $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+        // Check for items
+        if ($fieldConfig['type'] === 'select' && is_array($fieldConfig['items'] ?? false)) {
+            foreach ($fieldConfig['items'] as $iVal) {
+                $itemIdentifier = (string)$iVal[1];
+                if ($GLOBALS['BE_USER']->checkAuthMode($table, $field, $itemIdentifier, $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode'])) {
+                    $allowDenyOptions[] = $itemIdentifier;
+                }
+            }
+        }
+        return $allowDenyOptions;
+    }
+
+    /**
+     * Get allowed table / fieldnames for current backend user.
+     * Only consider table / fields in $searchFields
+     *
+     * @param array $searchFields array of 'table' => ['field1, field2', ....]
+     *   in which linkvalidator searches for broken links
+     * @return array
+     */
+    protected function getAllowedFieldsForCurrentUser(array $searchFields = []): array
+    {
+        if (!$searchFields) {
+            return [];
+        }
+
+        $allowedFields = [];
+
+        foreach ($searchFields as $table => $fieldList) {
+            if (!$GLOBALS['BE_USER']->isAdmin() && !$GLOBALS['BE_USER']->check('tables_modify', $table)) {
+                // table not allowed
+                continue;
+            }
+            foreach ($fieldList as $field) {
+                $isExcludeField = $GLOBALS['TCA'][$table]['columns'][$field]['exclude'] ?? false;
+                if (!$GLOBALS['BE_USER']->isAdmin()
+                    && $isExcludeField
+                    && !$GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $field)) {
+                    continue;
+                }
+                $allowedFields[$table][$field] = true;
+            }
+        }
+        return $allowedFields;
+    }
+
+    public function buildExpression(array $queriedTables, ExpressionBuilder $expressionBuilder): CompositeExpression
+    {
+        $constraints = [];
+
+        if ($this->allowedFields) {
+            $constraints = [
+                $expressionBuilder->orX(
+                // broken link is in page and page is editable
+                    $expressionBuilder->andX(
+                        $expressionBuilder->eq(
+                            'tx_linkvalidator_link.table_name',
+                            $this->queryBuilder->createNamedParameter('pages')
+                        ),
+                        QueryHelper::stripLogicalOperatorPrefix($GLOBALS['BE_USER']->getPagePermsClause(Permission::PAGE_EDIT))
+                    ),
+                    // OR broken link is in content and content is editable
+                    $expressionBuilder->andX(
+                        $expressionBuilder->neq(
+                            'tx_linkvalidator_link.table_name',
+                            $this->queryBuilder->createNamedParameter('pages')
+                        ),
+                        QueryHelper::stripLogicalOperatorPrefix($GLOBALS['BE_USER']->getPagePermsClause(Permission::CONTENT_EDIT))
+                    )
+                )
+            ];
+
+            // check if fields are editable
+            $additionalWhere = [];
+            foreach ($this->allowedFields as $table => $fields) {
+                foreach ($fields as $field => $value) {
+                    $additionalWhere[] = $expressionBuilder->andX(
+                        $expressionBuilder->eq(
+                            'tx_linkvalidator_link.table_name',
+                            $this->queryBuilder->createNamedParameter($table)
+                        ),
+                        $expressionBuilder->eq(
+                            'tx_linkvalidator_link.field',
+                            $this->queryBuilder->createNamedParameter($field)
+                        )
+                    );
+                }
+            }
+            if ($additionalWhere) {
+                $constraints[] = $expressionBuilder->orX(...$additionalWhere);
+            }
+        } else {
+            // add a constraint that will always return zero records because there are NO allowed fields
+            $constraints[] = $expressionBuilder->isNull('tx_linkvalidator_link.table_name');
+        }
+
+        foreach ($this->explicitAllowFields as $table => $field) {
+            $additionalWhere = [];
+            $additionalWhere[] = $expressionBuilder->andX(
+                $expressionBuilder->eq(
+                    'tx_linkvalidator_link.table_name',
+                    $this->queryBuilder->createNamedParameter($table)
+                ),
+                $expressionBuilder->in(
+                    'tx_linkvalidator_link.element_type',
+                    $this->queryBuilder->createNamedParameter(
+                        array_unique(current($field)),
+                        Connection::PARAM_STR_ARRAY
+                    )
+                )
+            );
+            $additionalWhere[] = $expressionBuilder->neq(
+                'tx_linkvalidator_link.table_name',
+                $this->queryBuilder->createNamedParameter($table)
+            );
+            if ($additionalWhere) {
+                $constraints[] = $expressionBuilder->orX(...$additionalWhere);
+            }
+        }
+
+        if ($this->allowedLanguages) {
+            $additionalWhere = [];
+            foreach ($this->allowedLanguages as $langId) {
+                $additionalWhere[] = $expressionBuilder->orX(
+                    $expressionBuilder->eq(
+                        'tx_linkvalidator_link.language',
+                        $this->queryBuilder->createNamedParameter($langId, \PDO::PARAM_INT)
+                    ),
+                    $expressionBuilder->eq(
+                        'tx_linkvalidator_link.language',
+                        $this->queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)
+                    )
+                );
+            }
+            $constraints[] = $expressionBuilder->orX(...$additionalWhere);
+        }
+        // If allowed languages is empty: all languages are allowed, so no constraint in this case
+
+        return $expressionBuilder->andX(...$constraints);
+    }
+}
diff --git a/typo3/sysext/linkvalidator/Classes/Report/LinkValidatorReport.php b/typo3/sysext/linkvalidator/Classes/Report/LinkValidatorReport.php
index 7243128656149561d3d62de0e13e5c3426a33571..a66d17d8bdbe9c354ffe6d57acb39dc2b9f226cc 100644
--- a/typo3/sysext/linkvalidator/Classes/Report/LinkValidatorReport.php
+++ b/typo3/sysext/linkvalidator/Classes/Report/LinkValidatorReport.php
@@ -143,6 +143,11 @@ class LinkValidatorReport
      */
     protected $view;
 
+    public function __construct()
+    {
+        $this->brokenLinkRepository = GeneralUtility::makeInstance(BrokenLinkRepository::class);
+    }
+
     /**
      * Init, called from parent object
      *
@@ -262,8 +267,8 @@ class LinkValidatorReport
             } else {
                 // mark broken links for last edited record as needing a recheck
                 $this->brokenLinkRepository->setNeedsRecheckForRecord(
-                    $this->lastEditedRecord['table'],
-                    (int)$this->lastEditedRecord['uid']
+                    (int)$this->lastEditedRecord['uid'],
+                    $this->lastEditedRecord['table']
                 );
             }
         }
@@ -324,7 +329,7 @@ class LinkValidatorReport
         }
 
         $this->pageRecord = BackendUtility::readPageAccess($this->id, $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW));
-        if ($this->id && is_array($this->pageRecord) || !$this->id && $this->getBackendUser()->isAdmin()) {
+        if (($this->id && is_array($this->pageRecord)) || (!$this->id && $this->getBackendUser()->isAdmin())) {
             $this->isAccessibleForCurrentUser = true;
         }
         // Don't access in workspace
@@ -402,7 +407,11 @@ class LinkValidatorReport
         $items = [];
         $rootLineHidden = $this->linkAnalyzer->getRootLineIsHidden($this->pObj->pageinfo);
         if (!$rootLineHidden || (bool)$this->modTS['checkhidden'] && !empty($linkTypes)) {
-            $brokenLinks = $this->brokenLinkRepository->getAllBrokenLinksForPages($this->getPageList(), $linkTypes);
+            $brokenLinks = $this->brokenLinkRepository->getAllBrokenLinksForPages(
+                $this->getPageList(),
+                $linkTypes,
+                $this->searchFields
+            );
             foreach ($brokenLinks as $row) {
                 $items[] = $this->renderTableRow($row['table_name'], $row);
             }
@@ -570,7 +579,7 @@ class LinkValidatorReport
     {
         $variables = [];
         $variables['totalCountLabel'] = BackendUtility::wrapInHelp('linkvalidator', 'checkboxes', $this->getLanguageService()->getLL('overviews.nbtotal'));
-        $variables['totalCount'] = $brokenLinkOverView['brokenlinkCount'] ?: '0';
+        $variables['totalCount'] = $brokenLinkOverView['total'] ?: '0';
         $variables['optionsByType'] = [];
         $linkTypes = GeneralUtility::trimExplode(',', $this->modTS['linktypes'] ?? '', true);
         $availableLinkTypes = array_keys($this->hookObjectsArr);
diff --git a/typo3/sysext/linkvalidator/Classes/Repository/BrokenLinkRepository.php b/typo3/sysext/linkvalidator/Classes/Repository/BrokenLinkRepository.php
index 36bf60b38079a521a823aeef3e71f0a60dfc057b..38c85c01dffc95b5969774f6c676a7763695f76f 100644
--- a/typo3/sysext/linkvalidator/Classes/Repository/BrokenLinkRepository.php
+++ b/typo3/sysext/linkvalidator/Classes/Repository/BrokenLinkRepository.php
@@ -19,6 +19,7 @@ namespace TYPO3\CMS\Linkvalidator\Repository;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Linkvalidator\QueryRestrictions\EditableRestriction;
 
 /**
  * Repository for finding broken links that were detected previously.
@@ -90,17 +91,27 @@ class BrokenLinkRepository
      * grouped by the link_type.
      *
      * @param array $pageIds
+     * @param array $searchFields [ table => [field1, field2, ...], ...]
      * @return array
      */
-    public function getNumberOfBrokenLinksForRecordsOnPages(array $pageIds): array
+    public function getNumberOfBrokenLinksForRecordsOnPages(array $pageIds, array $searchFields): array
     {
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
             ->getQueryBuilderForTable(static::TABLE);
         $queryBuilder->getRestrictions()->removeAll();
-
+        if (!$GLOBALS['BE_USER']->isAdmin()) {
+            $queryBuilder->getRestrictions()
+                ->add(GeneralUtility::makeInstance(EditableRestriction::class, $searchFields, $queryBuilder));
+        }
         $statement = $queryBuilder->select('link_type')
-            ->addSelectLiteral($queryBuilder->expr()->count('uid', 'amount'))
+            ->addSelectLiteral($queryBuilder->expr()->count(static::TABLE . '.uid', 'amount'))
             ->from(static::TABLE)
+            ->join(
+                static::TABLE,
+                'pages',
+                'pages',
+                $queryBuilder->expr()->eq('record_pid', $queryBuilder->quoteIdentifier('pages.uid'))
+            )
             ->where(
                 $queryBuilder->expr()->orX(
                     $queryBuilder->expr()->andX(
@@ -122,9 +133,12 @@ class BrokenLinkRepository
             ->groupBy('link_type')
             ->execute();
 
-        $result = [];
+        $result = [
+            'total' => 0
+        ];
         while ($row = $statement->fetch()) {
             $result[$row['link_type']] = $row['amount'];
+            $result['total']+= $row['amount'];
         }
         return $result;
     }
@@ -205,17 +219,31 @@ class BrokenLinkRepository
     /**
      * Prepare database query with pageList and keyOpt data.
      *
+     * This takes permissions of current BE user into account
+     *
      * @param int[] $pageIds Pages to check for broken links
      * @param string[] $linkTypes Link types to validate
+     * @param string[] $searchFields table => [fields1, field2, ...], ... : fields in which linkvalidator should
+     *   search for broken links
      * @return array
      */
-    public function getAllBrokenLinksForPages(array $pageIds, array $linkTypes): array
+    public function getAllBrokenLinksForPages(array $pageIds, array $linkTypes, array $searchFields = []): array
     {
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
             ->getQueryBuilderForTable(self::TABLE);
+        if (!$GLOBALS['BE_USER']->isAdmin()) {
+            $queryBuilder->getRestrictions()
+                ->add(GeneralUtility::makeInstance(EditableRestriction::class, $searchFields, $queryBuilder));
+        }
         $records = $queryBuilder
-            ->select('*')
+            ->select(self::TABLE . '.*')
             ->from(self::TABLE)
+            ->join(
+                'tx_linkvalidator_link',
+                'pages',
+                'pages',
+                $queryBuilder->expr()->eq('tx_linkvalidator_link.record_pid', $queryBuilder->quoteIdentifier('pages.uid'))
+            )
             ->where(
                 $queryBuilder->expr()->orX(
                     $queryBuilder->expr()->andX(
@@ -238,13 +266,13 @@ class BrokenLinkRepository
                     $queryBuilder->createNamedParameter($linkTypes, Connection::PARAM_STR_ARRAY)
                 )
             )
-            ->orderBy('record_uid')
-            ->addOrderBy('uid')
+            ->orderBy('tx_linkvalidator_link.record_uid')
+            ->addOrderBy('tx_linkvalidator_link.uid')
             ->execute()
             ->fetchAll();
         foreach ($records as &$record) {
             $response = json_decode($record['url_response'], true);
-            // Fallback mechansim to still support the old serialized data, could be removed in TYPO3 v12 or later
+            // Fallback mechanism to still support the old serialized data, could be removed in TYPO3 v12 or later
             if ($response === null) {
                 $response = unserialize($record['url_response'], ['allowed_classes' => false]);
             }
diff --git a/typo3/sysext/linkvalidator/Classes/Task/ValidatorTask.php b/typo3/sysext/linkvalidator/Classes/Task/ValidatorTask.php
index ef246de3329c37812f15d88c9ac6bc42bfe218ca..30d9362d51737566bee6b889b802baa97304a2fa 100644
--- a/typo3/sysext/linkvalidator/Classes/Task/ValidatorTask.php
+++ b/typo3/sysext/linkvalidator/Classes/Task/ValidatorTask.php
@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MailUtility;
 use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
+use TYPO3\CMS\Linkvalidator\Repository\BrokenLinkRepository;
 use TYPO3\CMS\Scheduler\Task\AbstractTask;
 
 /**
@@ -128,6 +129,9 @@ class ValidatorTask extends AbstractTask
      */
     protected $languageFile = 'LLL:EXT:linkvalidator/Resources/Private/Language/locallang.xlf';
 
+    /** @var BrokenLinkRepository */
+    protected $brokenLinkRepository;
+
     /**
      * Get the value of the protected property email
      *
@@ -256,6 +260,7 @@ class ValidatorTask extends AbstractTask
      */
     public function execute()
     {
+        $this->brokenLinkRepository = GeneralUtility::makeInstance(BrokenLinkRepository::class);
         $this->setCliArguments();
         $this->templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
         $successfullyExecuted = true;
@@ -343,12 +348,12 @@ class ValidatorTask extends AbstractTask
             $processor->init($searchFields, $pageIds, $modTs);
             if (!empty($this->email)) {
                 $oldLinkCounts = $processor->getLinkCounts();
-                $this->oldTotalBrokenLink += $oldLinkCounts['brokenlinkCount'];
+                $this->oldTotalBrokenLink += $oldLinkCounts['total'];
             }
             $processor->getLinkStatistics($linkTypes, $modTs['checkhidden']);
             if (!empty($this->email)) {
                 $linkCounts = $processor->getLinkCounts();
-                $this->totalBrokenLink += $linkCounts['brokenlinkCount'];
+                $this->totalBrokenLink += $linkCounts['total'];
                 $pageSections = $this->buildMail($page, $pageIds, $linkCounts, $oldLinkCounts);
             }
         }
@@ -547,7 +552,7 @@ class ValidatorTask extends AbstractTask
             BackendUtility::getRecord('pages', $curPage)
         );
         $content = '';
-        if ($markerArray['brokenlinkCount'] > 0) {
+        if ($markerArray['total'] > 0) {
             $content = $this->templateService->substituteMarkerArray(
                 $pageSectionHtml,
                 $markerArray,
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/BrokenLinkRepositoryTest.php b/typo3/sysext/linkvalidator/Tests/Functional/Repository/BrokenLinkRepositoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..77fafb17e68ed5d3f1746f195cf45ed5ba421939
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/BrokenLinkRepositoryTest.php
@@ -0,0 +1,723 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Linkvalidator\Tests\Functional\Repository;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\EventDispatcher\EventDispatcherInterface;
+use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
+use TYPO3\CMS\Linkvalidator\Repository\BrokenLinkRepository;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+class BrokenLinkRepositoryTest extends FunctionalTestCase
+{
+    /**
+     * @var array
+     */
+    protected $coreExtensionsToLoad = [
+        'linkvalidator',
+        'seo'
+    ];
+
+    /**
+     * @var BrokenLinkRepository
+     */
+    protected $brokenLinksRepository;
+
+    protected $beusers = [
+        'admin' => [
+            'fixture' => 'PACKAGE:typo3/testing-framework/Resources/Core/Functional/Fixtures/be_users.xml',
+            'uid' => 1,
+            'groupFixture' => ''
+        ],
+        'no group' => [
+            'fixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml',
+            'uid' => 2,
+            'groupFixture' => ''
+        ],
+        // write access to pages, tt_content
+        'group 1' => [
+            'fixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml',
+            'uid' => 3,
+            'groupFixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml'
+        ],
+        // write access to pages, tt_content, exclude field pages.header_link
+        'group 2' => [
+            'fixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml',
+            'uid' => 4,
+            'groupFixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml'
+        ],
+        // write access to pages, tt_content (restricted to default language)
+        'group 3' => [
+            'fixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml',
+            'uid' => 5,
+            'groupFixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml'
+        ],
+        // group 6: access to all, but restricted via explicit allow to CType=texmedia and text
+        'group 6' => [
+            'fixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml',
+            'uid' => 6,
+            'groupFixture' => 'EXT:linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml'
+        ],
+
+    ];
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        Bootstrap::initializeLanguageObject();
+
+        $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode'] = 'explicitAllow';
+        $this->brokenLinksRepository = new BrokenLinkRepository();
+    }
+
+    public function getLinkCountsForPagesAndLinktypesReturnsCorrectCountForUserDataProvider()
+    {
+        yield 'Admin user should see all broken links' =>
+        [
+            // backendUser: 1=admin
+            $this->beusers['admin'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'db' => 1,
+                'file' => 1,
+                'external' => 2,
+                'total' => 4,
+            ]
+        ];
+        yield 'User with no group should see none' =>
+        [
+            // backend user
+            $this->beusers['no group'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'total' => 0,
+            ]
+        ];
+        yield 'User with permission to pages but not to specific tables should see none' =>
+        [
+            // backend user
+            $this->beusers['no group'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_2.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'total' => 0,
+            ]
+        ];
+        yield 'User with permission to pages and to specific tables, but no exclude fields should see 3 of 4 broken links' =>
+        [
+            // backend user
+            $this->beusers['group 1'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_3.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'db' => 1,
+                'file' => 1,
+                'external' => 1,
+                'total' => 3
+            ]
+        ];
+        yield 'User with permission to pages, specific tables and exclude fields should see all broken links' =>
+        [
+            // backend user
+            $this->beusers['group 2'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_4.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'db' => 1,
+                'file' => 1,
+                'external' => 2,
+                'total' => 4
+            ]
+        ];
+        yield 'User has write permission only for Ctype textmedia and text, should see only broken links from textmedia records' =>
+        [
+            // backend user
+            $this->beusers['group 6'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_6_explicit_allow.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'external' => 1,
+                'total' => 1
+            ]
+        ];
+
+        yield 'User has write permission only for default language and should see only 1 of 2 broken links' =>
+        [
+            // backend user
+            $this->beusers['group 3'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_5.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                'external' => 1,
+                'total' => 1
+            ]
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider getLinkCountsForPagesAndLinktypesReturnsCorrectCountForUserDataProvider
+     */
+    public function getLinkCountsForPagesAndLinktypesReturnsCorrectCountForUser(
+        array $beuser,
+        string $inputFile,
+        array $pidList,
+        array $expectedOutput
+    ) {
+        $config = [
+            'db' => '1',
+            'file' => '1',
+            'external' => '1',
+            'linkhandler' => '1'
+
+        ];
+
+        $tsConfig = [
+            'searchFields.' => [
+                'pages' => 'media,url,canonical_link',
+                'tt_content' => 'bodytext,header_link,records'
+            ],
+            'linktypes' => 'db,file,external,linkhandler',
+            'checkhidden' => '0',
+            'linkhandler' => [
+                'reportHiddenRecords' => '0'
+            ]
+        ];
+
+        $searchFields = $tsConfig['searchFields.'];
+        foreach ($searchFields as $table => $fields) {
+            $searchFields[$table] = explode(',', $fields);
+        }
+
+        $this->setupBackendUser($beuser['uid'], $beuser['fixture'], $beuser['groupFixture']);
+
+        $this->importDataSet($inputFile);
+
+        $linkAnalyzer = new LinkAnalyzer(
+            $this->prophesize(EventDispatcherInterface::class)->reveal(),
+            $this->brokenLinksRepository
+        );
+        $linkAnalyzer->init($searchFields, implode(',', $pidList), $tsConfig);
+        $linkAnalyzer->getLinkStatistics($config);
+        $result = $this->brokenLinksRepository->getNumberOfBrokenLinksForRecordsOnPages(
+            $pidList,
+            $searchFields
+        );
+
+        self::assertEquals($expectedOutput, $result);
+    }
+
+    public function getAllBrokenLinksForPagesReturnsCorrectCountForUserDataProvider()
+    {
+        yield 'Admin user should see all broken links' =>
+        [
+            // backendUser: 1=admin
+            $this->beusers['admin'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input.xml',
+            //pids
+            [1],
+            // count
+            4
+        ];
+
+        yield 'User with no group should see none' =>
+        [
+            // backend user
+            $this->beusers['no group'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input.xml',
+            //pids
+            [1],
+            // count
+            0
+        ];
+        yield 'User with permission to pages but not to specific tables should see none' =>
+        [
+            // backend user
+            $this->beusers['no group'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_2.xml',
+            //pids
+            [1],
+            // count
+            0
+        ];
+        yield 'User with permission to pages and to specific tables, but no exclude fields should see 3 of 4 broken links' =>
+        [
+            // backend user
+            $this->beusers['group 1'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_3.xml',
+            //pids
+            [1],
+            // count
+            3
+        ];
+        yield 'User with permission to pages, specific tables and exclude fields should see all broken links' =>
+        [
+            // backend user
+            $this->beusers['group 2'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_4.xml',
+            //pids
+            [1],
+            // count
+            4
+        ];
+        yield 'User has write permission only for Ctype textmedia and text, should see only broken links from textmedia records' =>
+        [
+            // backend user
+            $this->beusers['group 6'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_6_explicit_allow.xml',
+            //pids
+            [1],
+            // count
+            1
+        ];
+
+        yield 'User has write permission only for default language and should see only 1 of 2 broken links' =>
+        [
+            // backend user
+            $this->beusers['group 3'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_5.xml',
+            //pids
+            [1],
+            // count
+            1
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider getAllBrokenLinksForPagesReturnsCorrectCountForUserDataProvider
+     */
+    public function getAllBrokenLinksForPagesReturnsCorrectCountForUser(
+        array $beuser,
+        string $inputFile,
+        array $pidList,
+        int $expectedCount
+    ) {
+        $config = [
+            'db' => '1',
+            'file' => '1',
+            'external' => '1',
+            'linkhandler' => '1'
+
+        ];
+
+        $linkTypes = [
+            'db',
+            'file',
+            'external'
+        ];
+
+        $tsConfig = [
+            'searchFields.' => [
+                'pages' => 'media,url,canonical_link',
+                'tt_content' => 'bodytext,header_link,records'
+            ],
+            'linktypes' => 'db,file,external,linkhandler',
+            'checkhidden' => '0',
+            'linkhandler' => [
+                'reportHiddenRecords' => '0'
+            ]
+        ];
+
+        $searchFields = $tsConfig['searchFields.'];
+        foreach ($searchFields as $table => $fields) {
+            $searchFields[$table] = explode(',', $fields);
+        }
+
+        $this->setupBackendUser($beuser['uid'], $beuser['fixture'], $beuser['groupFixture']);
+
+        $this->importDataSet($inputFile);
+
+        $linkAnalyzer = new LinkAnalyzer(
+            $this->prophesize(EventDispatcherInterface::class)->reveal(),
+            $this->brokenLinksRepository
+        );
+        $linkAnalyzer->init($searchFields, implode(',', $pidList), $tsConfig);
+        $linkAnalyzer->getLinkStatistics($config);
+
+        $results = $this->brokenLinksRepository->getAllBrokenLinksForPages(
+            $pidList,
+            $linkTypes,
+            $searchFields
+        );
+
+        self::assertEquals($expectedCount, count($results));
+    }
+
+    public function getAllBrokenLinksForPagesReturnsCorrectValuesForUserDataProvider()
+    {
+        yield 'Admin user should see all broken links' =>
+        [
+            // backendUser: 1=admin
+            $this->beusers['admin'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                [
+                   'record_uid' => 1,
+                   'record_pid' => 1,
+                   'language' => 0,
+                   'headline' => 'link',
+                   'field' => 'bodytext',
+                   'table_name' => 'tt_content',
+                   'element_type' => 'textmedia',
+                   'link_title' => 'link',
+                   'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                   'link_type' => 'external',
+                   'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 2,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => '[No title]',
+                    'field' => 'header_link',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => null,
+                    'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                    'link_type' => 'external',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 3,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'broken link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'broken link',
+                    'url' => '85',
+                    'link_type' => 'db',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 5,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'broken link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'broken link',
+                    'url' => 'file:88',
+                    'link_type' => 'file',
+                    'needs_recheck' => 0
+                ],
+            ]
+        ];
+
+        yield 'User with no group should see none' =>
+        [
+            // backend user
+            $this->beusers['no group'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input.xml',
+            //pids
+            [1],
+            // expected result:
+            []
+        ];
+        yield 'User with permission to pages but not to specific tables should see none' =>
+        [
+            // backend user
+            $this->beusers['no group'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_2.xml',
+            //pids
+            [1],
+            // expected result:
+            []
+        ];
+        yield 'User with permission to pages and to specific tables, but no exclude fields should see 3 of 4 broken links' =>
+        [
+            // backend user
+            $this->beusers['group 1'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_3.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                [
+                    'record_uid' => 1,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'link',
+                    'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                    'link_type' => 'external',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 3,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'broken link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'broken link',
+                    'url' => '85',
+                    'link_type' => 'db',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 5,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'broken link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'broken link',
+                    'url' => 'file:88',
+                    'link_type' => 'file',
+                    'needs_recheck' => 0
+                ],
+            ]
+        ];
+        yield 'User with permission to pages, specific tables and exclude fields should see all broken links' =>
+        [
+            // backend user
+            $this->beusers['group 2'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_4.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                [
+                    'record_uid' => 1,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'link',
+                    'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                    'link_type' => 'external',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 2,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => '[No title]',
+                    'field' => 'header_link',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => null,
+                    'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                    'link_type' => 'external',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 3,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'broken link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'broken link',
+                    'url' => '85',
+                    'link_type' => 'db',
+                    'needs_recheck' => 0
+                ],
+                [
+                    'record_uid' => 5,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'broken link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'broken link',
+                    'url' => 'file:88',
+                    'link_type' => 'file',
+                    'needs_recheck' => 0
+                ],
+            ]
+        ];
+        yield 'User has write permission only for Ctype textmedia and text, should see only broken links from textmedia records' =>
+        [
+            // backend user
+            $this->beusers['group 6'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_6_explicit_allow.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                [
+                    'record_uid' => 1,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'link',
+                    'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                    'link_type' => 'external',
+                    'needs_recheck' => 0
+                ],
+            ]
+        ];
+
+        yield 'User has write permission only for default language and should see only 1 of 2 broken links' =>
+        [
+            // backend user
+            $this->beusers['group 3'],
+            // input file for DB
+            __DIR__ . '/Fixtures/input_permissions_user_5.xml',
+            //pids
+            [1],
+            // expected result:
+            [
+                [
+                    'record_uid' => 1,
+                    'record_pid' => 1,
+                    'language' => 0,
+                    'headline' => 'link',
+                    'field' => 'bodytext',
+                    'table_name' => 'tt_content',
+                    'element_type' => 'textmedia',
+                    'link_title' => 'link',
+                    'url' => 'https://sfsfsfsfdfsfsdfsf/sfdsfsds',
+                    'link_type' => 'external',
+                    'needs_recheck' => 0
+                ],
+            ]
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider getAllBrokenLinksForPagesReturnsCorrectValuesForUserDataProvider
+     */
+    public function getAllBrokenLinksForPagesReturnsCorrectValuesForUser(
+        array $beuser,
+        string $inputFile,
+        array $pidList,
+        array $expectedResult
+    ) {
+        $config = [
+            'db' => '1',
+            'file' => '1',
+            'external' => '1',
+            'linkhandler' => '1'
+
+        ];
+
+        $linkTypes = [
+            'db',
+            'file',
+            'external'
+        ];
+
+        $tsConfig = [
+            'searchFields.' => [
+                'pages' => 'media,url,canonical_link',
+                'tt_content' => 'bodytext,header_link,records'
+            ],
+            'linktypes' => 'db,file,external,linkhandler',
+            'checkhidden' => '0',
+            'linkhandler' => [
+                'reportHiddenRecords' => '0'
+            ]
+        ];
+
+        $searchFields = $tsConfig['searchFields.'];
+        foreach ($searchFields as $table => $fields) {
+            $searchFields[$table] = explode(',', $fields);
+        }
+
+        $this->setupBackendUser($beuser['uid'], $beuser['fixture'], $beuser['groupFixture']);
+
+        $this->importDataSet($inputFile);
+
+        $linkAnalyzer = new LinkAnalyzer(
+            $this->prophesize(EventDispatcherInterface::class)->reveal(),
+            $this->brokenLinksRepository
+        );
+        $linkAnalyzer->init($searchFields, implode(',', $pidList), $tsConfig);
+        $linkAnalyzer->getLinkStatistics($config);
+
+        $results = $this->brokenLinksRepository->getAllBrokenLinksForPages(
+            $pidList,
+            $linkTypes,
+            $searchFields
+        );
+
+        foreach ($results as &$result) {
+            unset($result['url_response']);
+            unset($result['uid']);
+            unset($result['last_check']);
+        }
+        self::assertEquals($expectedResult, $results);
+    }
+
+    protected function setupBackendUser(int $uid, string $fixtureFile, string $groupFixtureFile)
+    {
+        if ($groupFixtureFile) {
+            $this->importDataSet($groupFixtureFile);
+        }
+        $this->backendUserFixture = $fixtureFile;
+        $this->setUpBackendUserFromFixture($uid);
+    }
+}
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml
new file mode 100644
index 0000000000000000000000000000000000000000..511c79f6e21acd406a40407b700cf12f279f44e9
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/be_groups.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <be_groups>
+        <uid>1</uid>
+        <pid>0</pid>
+        <tstamp>1366642540</tstamp>
+        <tables_modify>pages,tt_content</tables_modify>
+        <explicit_allowdeny>tt_content:CType:text:ALLOW,tt_content:CType:textmedia:ALLOW</explicit_allowdeny>
+    </be_groups>
+    <be_groups>
+        <uid>2</uid>
+        <pid>0</pid>
+        <tstamp>1366642540</tstamp>
+        <tables_modify>pages,tt_content</tables_modify>
+        <non_exclude_fields>tt_content:header_link</non_exclude_fields>
+        <explicit_allowdeny>tt_content:CType:text:ALLOW,tt_content:CType:textmedia:ALLOW</explicit_allowdeny>
+    </be_groups>
+    <be_groups>
+        <uid>3</uid>
+        <pid>0</pid>
+        <tstamp>1366642540</tstamp>
+        <tables_modify>pages,tt_content</tables_modify>
+        <allowed_languages>0</allowed_languages>
+        <explicit_allowdeny>tt_content:CType:text:ALLOW,tt_content:CType:textmedia:ALLOW</explicit_allowdeny>
+    </be_groups>
+
+    <!-- group 6: editors with access to all, but only CType=textmedia and text via explicit allow -->
+    <be_groups>
+        <uid>6</uid>
+        <pid>0</pid>
+        <tstamp>1366642540</tstamp>
+        <tables_modify>pages,tt_content</tables_modify>
+        <explicit_allowdeny>tt_content:CType:text:ALLOW,tt_content:CType:textmedia:ALLOW</explicit_allowdeny>
+    </be_groups>
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e8df1d0f7e7fbbbf0cb09b0dcd18ba373eafd5f0
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/be_users.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+	<be_users>
+		<uid>2</uid>
+		<pid>0</pid>
+		<username>plain_editor</username>
+        <realName>Editor with no group</realName>
+		<password>$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1</password> <!-- password -->
+		<admin>0</admin>
+		<disableIPlock>1</disableIPlock>
+		<lastlogin>1371033743</lastlogin>
+		<createdByAction>0</createdByAction>
+		<workspace_id>0</workspace_id>
+	</be_users>
+
+    <!-- editor with access to tables via group -->
+    <be_users>
+        <uid>3</uid>
+        <pid>0</pid>
+        <username>simple_editor1</username>
+        <realName>Editor with group 1</realName>
+        <usergroup>1</usergroup>
+        <password>$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1</password> <!-- password -->
+        <admin>0</admin>
+        <disableIPlock>1</disableIPlock>
+        <lastlogin>1371033743</lastlogin>
+        <createdByAction>0</createdByAction>
+        <workspace_id>0</workspace_id>
+    </be_users>
+
+    <!-- editor with access to tables and excludefiels via group -->
+    <be_users>
+        <uid>4</uid>
+        <pid>0</pid>
+        <username>simple_editor2</username>
+        <realName>Editor with group 2</realName>
+        <usergroup>2</usergroup>
+        <password>$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1</password> <!-- password -->
+        <admin>0</admin>
+        <disableIPlock>1</disableIPlock>
+        <lastlogin>1371033743</lastlogin>
+        <createdByAction>0</createdByAction>
+        <workspace_id>0</workspace_id>
+    </be_users>
+
+    <!-- editor with access to tables, limited to default language -->
+    <be_users>
+        <uid>5</uid>
+        <pid>0</pid>
+        <username>simple_editor3</username>
+        <realName>Editor with group 3</realName>
+        <usergroup>3</usergroup>
+        <password>$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1</password> <!-- password -->
+        <admin>0</admin>
+        <disableIPlock>1</disableIPlock>
+        <lastlogin>1371033743</lastlogin>
+        <createdByAction>0</createdByAction>
+        <workspace_id>0</workspace_id>
+    </be_users>
+
+    <!-- user 6: editor with access to all, but only CType=textmedia and text via explicit allow -->
+    <be_users>
+        <uid>6</uid>
+        <pid>0</pid>
+        <username>simple_editor6</username>
+        <realName>Editor with group 6</realName>
+        <usergroup>6</usergroup>
+        <password>$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1</password> <!-- password -->
+        <admin>0</admin>
+        <disableIPlock>1</disableIPlock>
+        <lastlogin>1371033743</lastlogin>
+        <createdByAction>0</createdByAction>
+        <workspace_id>0</workspace_id>
+    </be_users>
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7dd9c7e3dc44c8e96b7ebe7e71c15239f3586a16
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+    </pages>
+    <!-- external -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+    <tt_content>
+        <uid>2</uid>
+        <pid>1</pid>
+        <header_link>https://sfsfsfsfdfsfsdfsf/sfdsfsds</header_link>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- page -->
+    <tt_content>
+        <uid>3</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://page?uid=85&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- file -->
+    <tt_content>
+        <uid>5</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://file?uid=88&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_group.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_group.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d29a39db86a33d0246c9121efc7d131954dd58f4
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_group.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <perms_group>1</perms_group>
+        <!-- Permission::CONTENT_EDIT | Permission::PAGE_EDIT -->
+        <perms_user>18</perms_user>
+    </pages>
+
+    <!-- external -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- page -->
+    <tt_content>
+        <uid>3</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://page?uid=85&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- file -->
+    <tt_content>
+        <uid>5</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://file?uid=88&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_2.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c45d3aad817260c047cfc4dd7647e79ec40c542b
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_2.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <perms_userid>2</perms_userid>
+        <!-- Permission::CONTENT_EDIT | Permission::PAGE_EDIT -->
+        <perms_user>18</perms_user>
+    </pages>
+
+    <!-- external -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- page -->
+    <tt_content>
+        <uid>3</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://page?uid=85&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- file -->
+    <tt_content>
+        <uid>5</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://file?uid=88&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_3.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_3.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b9eb96931d2daf6da96ad726ece6ff1dfeb70ffe
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_3.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <perms_userid>3</perms_userid>
+        <!-- Permission::CONTENT_EDIT | Permission::PAGE_EDIT -->
+        <perms_user>18</perms_user>
+    </pages>
+
+    <!-- external -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+    <tt_content>
+        <uid>2</uid>
+        <pid>1</pid>
+        <header_link>https://sfsfsfsfdfsfsdfsf/sfdsfsds</header_link>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- page -->
+    <tt_content>
+        <uid>3</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://page?uid=85&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- file -->
+    <tt_content>
+        <uid>5</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://file?uid=88&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_4.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_4.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9aebe00c563694f63c1502f6a3982ee654562e83
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_4.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <perms_userid>4</perms_userid>
+        <!-- Permission::CONTENT_EDIT | Permission::PAGE_EDIT -->
+        <perms_user>18</perms_user>
+    </pages>
+
+    <!-- external -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+    <tt_content>
+        <uid>2</uid>
+        <pid>1</pid>
+        <header_link>https://sfsfsfsfdfsfsdfsf/sfdsfsds</header_link>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- page -->
+    <tt_content>
+        <uid>3</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://page?uid=85&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- file -->
+    <tt_content>
+        <uid>5</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;t3://file?uid=88&quot;&gt;broken link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_5.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_5.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e69790676137425fd54f0f92b636f6114bf87abe
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_5.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <perms_userid>5</perms_userid>
+        <!-- Permission::CONTENT_EDIT | Permission::PAGE_EDIT -->
+        <perms_user>18</perms_user>
+    </pages>
+
+    <!-- default language -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+        <sys_language_uid>0</sys_language_uid>
+    </tt_content>
+
+    <!-- other language -->
+    <tt_content>
+        <uid>2</uid>
+        <pid>1</pid>
+        <header_link>https://sfsfsfsfdfsfsdfsf/sfdsfsds</header_link>
+        <CType>textmedia</CType>
+        <sys_language_uid>1</sys_language_uid>
+    </tt_content>
+
+</dataset>
diff --git a/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_6_explicit_allow.xml b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_6_explicit_allow.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7624e10cdb3cb55618a1e137a4ebebc5980328c9
--- /dev/null
+++ b/typo3/sysext/linkvalidator/Tests/Functional/Repository/Fixtures/input_permissions_user_6_explicit_allow.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <perms_userid>6</perms_userid>
+        <!-- Permission::CONTENT_EDIT | Permission::PAGE_EDIT -->
+        <perms_user>18</perms_user>
+    </pages>
+
+    <!-- textmedia -->
+    <tt_content>
+        <uid>1</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textmedia</CType>
+    </tt_content>
+
+    <!-- textpic -->
+    <tt_content>
+        <uid>2</uid>
+        <pid>1</pid>
+        <bodytext>&lt;p&gt;&lt;a href=&quot;https://sfsfsfsfdfsfsdfsf/sfdsfsds&quot;&gt;link&lt;/a&gt;&lt;/p&gt;</bodytext>
+        <CType>textpic</CType>
+    </tt_content>
+</dataset>
diff --git a/typo3/sysext/linkvalidator/ext_tables.sql b/typo3/sysext/linkvalidator/ext_tables.sql
index 401cc85e9c3076ed5c61f23b782fc7978d818dbe..91b4b19d6564c89d77e54bfbe8b305b664299569 100644
--- a/typo3/sysext/linkvalidator/ext_tables.sql
+++ b/typo3/sysext/linkvalidator/ext_tables.sql
@@ -2,9 +2,11 @@ CREATE TABLE tx_linkvalidator_link (
 	uid int(11) NOT NULL auto_increment,
 	record_uid int(11) DEFAULT '0' NOT NULL,
 	record_pid int(11) DEFAULT '0' NOT NULL,
+	language int(11) DEFAULT '-1' NOT NULL,
 	headline varchar(255) DEFAULT '' NOT NULL,
 	field varchar(255) DEFAULT '' NOT NULL,
 	table_name varchar(255) DEFAULT '' NOT NULL,
+	element_type varchar(255) DEFAULT '' NOT NULL,
 	link_title text,
 	url text,
 	url_response text,