This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch db/8607
in repository https://gitbox.apache.org/repos/asf/allura.git

commit b77f66002d3adf3eae404988aef9a3874dd63db4
Author: Dave Brondsema <[email protected]>
AuthorDate: Fri May 15 16:51:36 2026 -0400

    [#8607] check app_config_id in update_forums
---
 ForgeDiscussion/forgediscussion/forum_main.py      |  5 ++-
 .../tests/functional/test_forum_admin.py           | 36 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/ForgeDiscussion/forgediscussion/forum_main.py 
b/ForgeDiscussion/forgediscussion/forum_main.py
index 9ab89f4c6..2c70cd47b 100644
--- a/ForgeDiscussion/forgediscussion/forum_main.py
+++ b/ForgeDiscussion/forgediscussion/forum_main.py
@@ -322,7 +322,10 @@ def set_value(forum, name, val):
             setattr(forum, name, val)
 
         for f in forum:
-            forum = DM.Forum.query.get(_id=ObjectId(str(f['id'])))
+            forum = DM.Forum.query.get(_id=ObjectId(str(f['id'])),
+                                       app_config_id=self.app.config._id)
+            if forum is None:
+                continue
             if f.get('delete'):
                 forum.deleted = True
                 M.AuditLog.log('deleted forum "{}" from {}'.format(
diff --git 
a/ForgeDiscussion/forgediscussion/tests/functional/test_forum_admin.py 
b/ForgeDiscussion/forgediscussion/tests/functional/test_forum_admin.py
index 72cf633d5..459f2c91a 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_forum_admin.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_forum_admin.py
@@ -18,9 +18,12 @@
 import logging
 
 import re
+from ming.odm import ThreadLocalODMSession
+from tg import tmpl_context as c
 from alluratest.controller import TestController
 from allura.lib import helpers as h
 from allura import model as M
+from allura.tests import decorators as td
 
 from forgediscussion import model as FM
 
@@ -320,3 +323,36 @@ def test_footer_monitoring_email(self):
                    0].kwargs['text'], email_tasks[0].kwargs['text']
         assert 'a project admin can change settings at 
http://localhost/p/test/admin/discussion/forums' in email_tasks[
             0].kwargs['text']
+
+    @td.with_tool('test2', 'Discussion', 'discussion')
+    def test_update_forums_rejects_foreign_forum(self):
+        # Create a forum in the test2 project's Discussion app (the victim).
+        h.set_context('test2', 'discussion', neighborhood='Projects')
+        victim_app_config_id = c.app.config._id
+        victim = FM.Forum(
+            app_config_id=victim_app_config_id,
+            shortname='victim',
+            name='Victim Forum',
+            description='original',
+        )
+        ThreadLocalODMSession.flush_all()
+        victim_id = victim._id
+
+        # Attacker is admin of project 'test' and posts to its update_forums 
with the victim's _id.
+        self.app.post('/admin/discussion/update_forums',
+                      params={'forum-0.delete': 'on',
+                              'forum-0.id': str(victim_id),
+                              'forum-0.name': 'Pwned',
+                              'forum-0.shortname': 'pwned',
+                              'forum-0.description': 'pwned',
+                              'forum-0.monitoring_email': ''})
+
+        # Victim forum in test2 must be untouched.
+        ThreadLocalODMSession.close_all()
+        h.set_context('test2', 'discussion', neighborhood='Projects')
+        reloaded = FM.Forum.query.get(_id=victim_id)
+        assert reloaded is not None
+        assert reloaded.deleted is False, 'foreign forum was deleted via 
cross-project update_forums'
+        assert reloaded.name == 'Victim Forum', 'foreign forum was renamed via 
cross-project update_forums'
+        assert reloaded.description == 'original'
+        assert reloaded.app_config_id == victim_app_config_id

Reply via email to