From 8f3a4e76eb13b30fb91cc9f0e02380ed247e93bb Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Fri, 6 Nov 2026 11:30:05 +0100 Subject: [PATCH] fix(security): Pods-Feldrechte fail-closed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fehlt pods_has_permissions() oder pods_permission(), gilt kein Pods-Feld mehr als unbeschränkt, sondern als nicht erlaubt (HIDDEN/READONLY). Co-Authored-By: Claude Opus 5.5 --- src/Integrations/Pods/PodsFieldSource.php | 7 ++++--- .../Integrations/Pods/PodsFieldSourceTest.php | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Integrations/Pods/PodsFieldSource.php b/src/Integrations/Pods/PodsFieldSource.php index 24a346d..b612cfa 100644 --- a/src/Integrations/Pods/PodsFieldSource.php +++ b/src/Integrations/Pods/PodsFieldSource.php @@ -50,11 +50,12 @@ final class PodsFieldSource implements FieldSource $this->loadPod = $loadPod ?? static fn (string $name): mixed => pods_api()->load_pod(['name' => $name]); $this->podFor = $podFor ?? static fn (string $name, int $id): mixed => pods($name, $id); $this->permitted = $permitted ?? static function (object $field): ?bool { - if (! function_exists('pods_has_permissions') || ! pods_has_permissions($field)) { - return null; + // Fail closed: without the Pods permission API no field counts as permitted. + if (! function_exists('pods_has_permissions') || ! function_exists('pods_permission')) { + return false; } - return function_exists('pods_permission') && (bool) pods_permission($field); + return pods_has_permissions($field) ? (bool) pods_permission($field) : null; }; } diff --git a/tests/Unit/Integrations/Pods/PodsFieldSourceTest.php b/tests/Unit/Integrations/Pods/PodsFieldSourceTest.php index e78c181..e078094 100644 --- a/tests/Unit/Integrations/Pods/PodsFieldSourceTest.php +++ b/tests/Unit/Integrations/Pods/PodsFieldSourceTest.php @@ -32,7 +32,7 @@ final class PodsFieldSourceTest extends TestCase private function source(?object $pod): PodsFieldSource { - return new PodsFieldSource(static fn (string $name) => $pod ?? false); + return new PodsFieldSource(static fn (string $name) => $pod ?? false, null, static fn (object $field): ?bool => null); } /** @return array> */ @@ -79,6 +79,19 @@ final class PodsFieldSourceTest extends TestCase self::assertSame(FieldDefinition::UNKNOWN, $fields['mystery']['status']); } + /** Fail-closed: without the Pods permission functions (not loaded in the unit run) no field counts as permitted. */ + public function testFieldIsHiddenWhenThePodsPermissionFunctionsAreMissing(): void + { + self::assertFalse(function_exists('pods_has_permissions')); + $pod = Mockery::mock(); + $pod->allows('get_type')->andReturn('post_type'); + $pod->allows('get_fields')->andReturn(['role' => $this->field('role', 'text')]); + + $fields = (new PodsFieldSource(static fn (string $name) => $pod))->fieldsFor('lit_person'); + + self::assertSame(FieldDefinition::HIDDEN, $fields[0]->status); + } + public function testParsesCustomSimpleChoices(): void { self::assertSame(