diff --git a/models/fixtures/team_unit.yml b/models/fixtures/team_unit.yml
index 5d2ba2fb6c..c5531aa57a 100644
--- a/models/fixtures/team_unit.yml
+++ b/models/fixtures/team_unit.yml
@@ -280,3 +280,9 @@
   team_id: 20
   type: 9 # package
   access_mode: 2
+
+-
+  id: 48
+  team_id: 2
+  type: 8
+  access_mode: 2
diff --git a/routers/web/web.go b/routers/web/web.go
index d31acc9726..f12e5c355a 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -263,9 +263,10 @@ func registerRoutes(m *web.Route) {
 		}
 	}
 
-	reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
+	reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode, ignoreGlobal bool) func(ctx *context.Context) {
 		return func(ctx *context.Context) {
-			if unitType.UnitGlobalDisabled() {
+			// only check global disabled units when ignoreGlobal is false
+			if !ignoreGlobal && unitType.UnitGlobalDisabled() {
 				ctx.NotFound(unitType.String(), nil)
 				return
 			}
@@ -842,7 +843,7 @@ func registerRoutes(m *web.Route) {
 			m.Group("", func() {
 				m.Get("", org.Projects)
 				m.Get("/{id}", org.ViewProject)
-			}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead))
+			}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true))
 			m.Group("", func() { //nolint:dupl
 				m.Get("/new", org.RenderNewProject)
 				m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
@@ -863,17 +864,17 @@ func registerRoutes(m *web.Route) {
 						m.Post("/move", org.MoveIssues)
 					})
 				})
-			}, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite), func(ctx *context.Context) {
+			}, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), func(ctx *context.Context) {
 				if ctx.ContextUser.IsIndividual() && ctx.ContextUser.ID != ctx.Doer.ID {
 					ctx.NotFound("NewProject", nil)
 					return
 				}
 			})
-		}, repo.MustEnableProjects)
+		})
 
 		m.Group("", func() {
 			m.Get("/code", user.CodeSearch)
-		}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead))
+		}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false))
 	}, ignSignIn, context_service.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code)
 
 	// ***** Release Attachment Download without Signin
diff --git a/tests/integration/org_project_test.go b/tests/integration/org_project_test.go
new file mode 100644
index 0000000000..4ae94b4d45
--- /dev/null
+++ b/tests/integration/org_project_test.go
@@ -0,0 +1,61 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+	"net/http"
+	"testing"
+
+	unit_model "code.gitea.io/gitea/models/unit"
+	"code.gitea.io/gitea/tests"
+)
+
+func TestOrgProjectAccess(t *testing.T) {
+	defer tests.PrepareTestEnv(t)()
+
+	// disable repo project unit
+	unit_model.DisabledRepoUnits = []unit_model.Type{unit_model.TypeProjects}
+
+	// repo project, 404
+	req := NewRequest(t, "GET", "/user2/repo1/projects")
+	MakeRequest(t, req, http.StatusNotFound)
+
+	// user project, 200
+	req = NewRequest(t, "GET", "/user2/-/projects")
+	MakeRequest(t, req, http.StatusOK)
+
+	// org project, 200
+	req = NewRequest(t, "GET", "/user3/-/projects")
+	MakeRequest(t, req, http.StatusOK)
+
+	// change the org's visibility to private
+	session := loginUser(t, "user2")
+	req = NewRequestWithValues(t, "POST", "/org/user3/settings", map[string]string{
+		"_csrf":      GetCSRF(t, session, "/user3/-/projects"),
+		"name":       "user3",
+		"visibility": "2",
+	})
+	session.MakeRequest(t, req, http.StatusSeeOther)
+
+	// user4 can still access the org's project because its team(team1) has the permission
+	session = loginUser(t, "user4")
+	req = NewRequest(t, "GET", "/user3/-/projects")
+	session.MakeRequest(t, req, http.StatusOK)
+
+	// disable team1's project unit
+	session = loginUser(t, "user2")
+	req = NewRequestWithValues(t, "POST", "/org/user3/teams/team1/edit", map[string]string{
+		"_csrf":       GetCSRF(t, session, "/user3/-/projects"),
+		"team_name":   "team1",
+		"repo_access": "specific",
+		"permission":  "read",
+		"unit_8":      "0",
+	})
+	session.MakeRequest(t, req, http.StatusSeeOther)
+
+	// user4 can no longer access the org's project
+	session = loginUser(t, "user4")
+	req = NewRequest(t, "GET", "/user3/-/projects")
+	session.MakeRequest(t, req, http.StatusNotFound)
+}