diff --git a/runbot/tests/__init__.py b/runbot/tests/__init__.py
index 188387ca..6fd7cc02 100644
--- a/runbot/tests/__init__.py
+++ b/runbot/tests/__init__.py
@@ -15,3 +15,4 @@ from . import test_commit
 from . import test_upgrade
 from . import test_dockerfile
 from . import test_host
+from . import test_web_search_read
diff --git a/runbot/tests/test_web_search_read.py b/runbot/tests/test_web_search_read.py
new file mode 100644
index 00000000..6a9ecf49
--- /dev/null
+++ b/runbot/tests/test_web_search_read.py
@@ -0,0 +1,99 @@
+import json
+import logging
+
+
+from odoo.tests.common import tagged, HttpCase, new_test_user
+from .common import RunbotCase
+
+_logger = logging.getLogger(__name__)
+
+
+@tagged('-at_install', 'post_install')
+class TestWebsearchReadAccess(HttpCase, RunbotCase):
+
+    def setUp(self):
+        super().setUp()
+        create_context = {'no_reset_password': True, 'mail_create_nolog': True, 'mail_create_nosubscribe': True, 'mail_notrack': True}
+        self.simple_user = new_test_user(self.env, login='simple', name='simple', password='simple', context=create_context)
+
+        runbot_module_category = self.env['ir.module.category'].search([['name', 'ilike', 'runbot']], limit=1)
+
+        self.other_project_group = self.env['res.groups'].create({
+            'name': 'Other Project',
+            'category_id': runbot_module_category.id,
+        })
+
+        self.other_project = self.env['runbot.project'].create({'name': 'Other Test Project', 'group_ids': self.other_project_group.ids})
+
+        self.repo_server_in_other_project = self.Repo.create({
+            'name': 'server',
+            'project_id': self.other_project.id,
+            'server_files': 'server.py',
+            'addons_paths': 'addons,core/addons'
+        })
+
+        self.remote_server_other_project = self.Remote.create({
+            'name': 'bla@example.com:base/server',
+            'repo_id': self.repo_server_in_other_project.id,
+            'token': '123',
+        })
+
+        self.initial_server_commit_other_project = self.Commit.create({
+            'name': 'deadbeef',
+            'repo_id': self.repo_server_in_other_project.id,
+            'date': '2024-12-07',
+            'subject': 'Foo bar commit',
+            'author': 'r23',
+            'author_email': 'r23@nowhere.com'
+        })
+
+        self.branch_server_other_project = self.Branch.create({
+            'name': '17.0-other-project-feature',
+            'remote_id': self.remote_server_other_project.id,
+            'is_pr': False,
+            'head': self.initial_server_commit_other_project.id,
+        })
+
+        self.stop_patcher('isfile')  # should not be patched during HttpCase, used in http.py
+
+    def test_web_search_read_user_access(self):
+        search_read_params = {
+                'uid': 711675,
+                'model': 'runbot.bundle',
+                'domain': json.dumps([('id', '=', self.master_bundle.id)]),
+                'specification': json.dumps({'name':{}})
+            }
+        res = self.url_open('http://127.0.0.1:8069/runbot/api/web_search_read', data=search_read_params)
+
+        self.assertEqual(res.status_code, 403, 'A non existing user should get a 403')
+        self.assertEqual(res.json(), {'error': 'Unauthorized'})
+
+        search_read_params['uid'] = self.simple_user.id
+        res = self.opener.post('http://127.0.0.1:8069/runbot/api/web_search_read', data=search_read_params)
+        self.assertEqual(res.status_code, 403, 'A user without a token should get a 403')
+        self.assertEqual(res.json(), {'error': 'Invalid user or token'})
+
+        self.simple_user.action_generate_token()
+        search_read_params['token'] = 'foobar'
+        res = self.opener.post('http://127.0.0.1:8069/runbot/api/web_search_read', data=search_read_params)
+        self.assertEqual(res.status_code, 403, 'A user without a token should get a 403')
+        self.assertEqual(res.json(), {'error': 'Invalid user or token'})
+
+        search_read_params['token'] = self.simple_user.runbot_api_token
+        res = self.opener.post('http://127.0.0.1:8069/runbot/api/web_search_read', data=search_read_params)
+        self.assertEqual(res.status_code, 200, 'A valid user with a valid token sould get a 200')
+
+        search_read_params['specification'] =  json.dumps({'priority': {}})
+        res = self.opener.post('http://127.0.0.1:8069/runbot/api/web_search_read', data=search_read_params)
+        self.assertEqual(res.status_code, 403, 'A valid user without proper group should not be able to read a field with a group restriction')
+        self.assertEqual(res.json(), {'error': 'Unauthorized'})
+
+        search_read_params.update({
+            'model': 'runbot.bundle',
+            'domain': json.dumps([('branch_ids', 'in', self.branch_server_other_project.id)]),
+            'specification': json.dumps({'name':{}}),
+        })
+        res = self.opener.post('http://127.0.0.1:8069/runbot/api/web_search_read', data=search_read_params)
+        self.assertEqual(res.json().get('records', []), [], 'A valid user without proper group should not be able to read objects from a another project with a group restriction')
+        self.assertEqual(res.status_code, 403, 'A valid user without proper group should not be able to read objects from a another project with a group restriction')
+        self.assertEqual(res.json(), {'error': 'Unauthorized'})