Skip to content

Fix #203: Info disclosure #208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Fix_HTMLi-AddMember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Hello

##Issue
This pull request serves as a placeholder for Issue ==> https://github.com/AIxBlock-2023/awesome-ai-dev-platform-opensource/issues/50

HTML injection is a type of injection vulnerability that occurs when a user is able to control an input point and is able to inject arbitrary HTML code into a vulnerable web application.

AIxBlock application service allows the execution of arbitrary HTML Injection payload on AIxBlock mail service through the "invited new members" email notification template.

##See below for screenshot.
https://drive.google.com/drive/folders/1IJAtg8wJoQKJ2MzKimP938f6CFeMOnZg?usp=sharing

##To Reproduce
Steps to reproduce the behavior:

- Go to "https://app.aixblock.io/user/organization'
- Go to Account Settings --> Organizations --> Add Member
- Scroll down to 'User Name' field and enter the payload (<\h1\>test.com<\/h1\> (please remove \)
- Enter the Victim's email address and forward


##Expected behavior
A clear and concise description of what you expected to happen.

- Form field should should be sanitized against meta characters
- Ensure the application logic also prevent the executions of injected payloads

27 changes: 27 additions & 0 deletions Fix_IDOR-on-Organization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Hello

##Issue
This pull request serves as a placeholder for Issue ==> https://github.com/AIxBlock-2023/awesome-ai-dev-platform-opensource/issues/47

The API endpoint "/api/organizations/{Orgaizatio-ID}/memberships" is vulnerable to Insecure Direct Object Reference (IDOR), allowing authenticated users to view any user's data by manipulating the "{Orgaizatio-ID}" value.

##To Reproduce
Steps to reproduce the behavior:

1- Go to 'https://app.aixblock.io/api/organizations/{Orgaizatio-ID}/memberships?page=1&page_size=9&project_id=&search='
2- Click on 'Enter any 4 digit integer e.g 6754'
3- Check the 'Server Response'

##Business Risk

1- Exposure of Any Organization information
2- Exposure of Any Organization Admin PII
3- Exposure of User Email Address, Phone number, Username, Full name, UUID & UID.

##Expected behavior

A clear and concise description of what you expected to happen.

Ensure SessionID and UserID matches the Organization ID before returning a 200 OK and Organization information.

Otherwise (i.e if the SessionID & UserID does not match the OrganizationID) Return 401 Unauthorized value.
13 changes: 13 additions & 0 deletions Fix_PrivilegeEscal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Hello

This pull request serves as a placeholder for Issue #58.

The file was added to meet the project’s submission requirements.

Remediation guide:

- DO not rely on front-end response before granting user access to sensitive functionalities.

- Ensure Super_Admin functionalities are not accessible to base_users and admins, by checking the permission level tied to the user session cookie or JWToken

- SUPER_ADMIN RIGHT should be tied to access token and session cookie upon account creation, and it should also be checked when request is sent to any SUPER_ADMIN endpoint.
10 changes: 10 additions & 0 deletions bugfix-0xygyn/fix-infodisclosure
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Recommended fix for security issue 203:

Since the "MarketPlace Model" functionality does not require any API calls to another user's profile,

Commenting out that API call to /api/user/(the 6 IDs called) in the code base is what is required to fix this vulnerability.

###COMMENT OUT THE API CALL TO THAT ENDPOINT.

Also, disabling the API endpoint /api/user/ID is required from the API Collection since /api/users/ID exist.

88 changes: 88 additions & 0 deletions bugfixes_0xygyn/bugfixes/0XYGYN_SECURITY_FIXES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Security Fixes

This document summarizes the patched vulnerabilities and provides file locations for the reported vulnerabilities listed below:

---

### #111
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:** POST /api/invite/csv
- **Affected Parameter:** `organizationId`

### #108
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:** POST /api/invite/csv
- **Affected Parameter:** `organizationId`
- **Vulnerability Type:** Broken Access Control (IDOR)

### #98
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:** POST /api/storages/link-global/1818/823/s3
- **Vulnerability Type:** Broken Access Control (IDOR)

### #97
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:** GET /api/storages/s3-server/1
- **Vulnerability Type:** Broken Access Control (IDOR)

### #95
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:**
- GET /api/storages/azure/5
- **Vulnerability Type:** Broken Access Control (IDOR)

### #94
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:**
- GET /api/storages/s3/ID
- **Vulnerability Type:** Broken Access Control (IDOR)

### #93
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:**
- GET /api/storages/s3/18
- **Vulnerability Type:** Broken Access Control (IDOR)

### #59
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:**
- GET https://app.aixblock.io/api/current-user/whoami
- **Vulnerability Type:** Privilege Escalation

### #47
- **Affected sub-domain:** https://app.aixblock.io/
- **Affected Endpoint:**
- GET /api/organizations/{Organization-ID}/memberships
- **Vulnerability Type:** Broken Access Control (IDOR)

---

## Fixed issues

- **IDOR vulnerabilities on storage detail endpoints** (#93, #94, #95, #97)
- **File:** `aixblock_core/io_storages/api.py`
- Added project permission checks in `ImportStorageDetailAPI.get_object` and `ExportStorageDetailAPI.get_object`.

- **IDOR on organization member listing** (#47)
- **File:** `aixblock_core/organizations/api.py`
- `OrganizationMemberListAPI.get_queryset` now verifies the requesting user belongs to the organization.

- **Unrestricted organization invitations** (#111, #108)
- **File:** `aixblock_core/organizations/api.py`
- `OrganizationInviteAPIByCSV.post` validates that the requester is an admin of the specified organization.

- **Privilege Escalation and Excessive data exposure in `whoami` endpoint** (#59)
- **File:** `aixblock_core/users/api.py`
- `UserWhoAmIAPI` uses `UserCompactSerializer` instead of `UserSerializer`.

---

## Paths and line references

| File | Lines |
|-----------------------------|------------------------|
| `io_storages/api.py` | see lines around 103 and 279 |
| `organizations/api.py` | lines around 158-170 and 426-437 |
| `users/api.py` | lines around 362-371 |
| `core/permissions.py` | lines around 112-121 |

121 changes: 121 additions & 0 deletions bugfixes_0xygyn/bugfixes/core/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
"""
import logging
import rules

from pydantic import BaseModel
from typing import Optional

from rest_framework.permissions import BasePermission

logger = logging.getLogger(__name__)


class AllPermissions(BaseModel):
organizations_create = 'organizations.create'
organizations_view = 'organizations.view'
organizations_change = 'organizations.change'
organizations_delete = 'organizations.delete'
organizations_invite = 'organizations.invite'
projects_create = 'projects.create'
projects_view = 'projects.view'
projects_change = 'projects.change'
projects_delete = 'projects.delete'
tasks_create = 'tasks.create'
tasks_view = 'tasks.view'
tasks_change = 'tasks.change'
tasks_delete = 'tasks.delete'
annotations_create = 'annotations.create'
annotations_view = 'annotations.view'
annotations_change = 'annotations.change'
annotations_delete = 'annotations.delete'
actions_perform = 'actions.perform'
predictions_any = 'predictions.any'
avatar_any = 'avatar.any'
labels_create = 'labels.create'
labels_view = 'labels.view'
labels_change = 'labels.change'
labels_delete = 'labels.delete'
model_marketplace_create = 'model_marketplace.create'
model_marketplace_view = 'model_marketplace.view'
model_marketplace_change = 'model_marketplace.change'
model_marketplace_delete = 'model_marketplace.delete'
orders_delete = 'orders.delete'
orders_view = 'orders.view'
orders_change = 'orders.change'
orders_create = 'orders.create'
reward_point_view = "reward_point.view"
reward_point_change = "reward_point.change"
reward_point_delete = "reward_point.delete"
reward_point_create = "reward_point.create"
installation_service_view = "installation_service.view"
installation_service_change = "installation_service.change"
installation_service_delete = "installation_service.delete"
installation_service_create = "installation_service.create"


all_permissions = AllPermissions()


class ViewClassPermission(BaseModel):
GET: Optional[str] = None
PATCH: Optional[str] = None
PUT: Optional[str] = None
DELETE: Optional[str] = None
POST: Optional[str] = None


def make_perm(name, pred, overwrite=False):
if rules.perm_exists(name):
if overwrite:
rules.remove_perm(name)
else:
return
rules.add_perm(name, pred)


for _, permission_name in all_permissions:
make_perm(permission_name, rules.is_authenticated)


class IsSuperAdmin(BasePermission):
"""
Allows access only to admin users.
"""

def has_permission(self, request, view):
return bool(request.user and request.user.is_superuser)

class IsSuperAdminOrg(BasePermission):
"""
Allows access only to admin org users.
"""

def has_permission(self, request, view):
try:
from organizations.models import OrganizationMember
from projects.models import Project

if 'project_id' in request.data:
project = Project.objects.get(id=request.data.get('project_id'))
else:
project = Project.objects.get(id=request.data.get('project'))
check_org_admin = OrganizationMember.objects.filter(organization_id = project.organization_id, user_id=request.user.id, is_admin=True).exists()
if not check_org_admin:
if not project.organization.created_by_id == request.user.id and not request.user.is_superuser:
return False
return True
except:
return True

def permission_org(user, project):
try:
from organizations.models import OrganizationMember

check_org_admin = OrganizationMember.objects.filter(organization_id = project.organization_id, user_id=user.id, is_admin=True).exists()
if not check_org_admin:
if not project.organization.created_by_id == user.id and not user.is_superuser:
return False
return True
except Exception:
return True
Loading