CVE-2024-29194 (published 2024-03-24T19:15Z)

OneUptime is a solution for monitoring and managing online services. The vulnerability lies in the improper validation of client-side stored data within the web application. Specifically, the is_master_admin key, stored in the local storage of the browser, can be manipulated by an attacker. By changing this key from false to true, the application grants administrative privileges to the user, without proper server-side validation.  This has been patched in 7.0.1815.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/OneUptime/oneuptime
commit_details: repo_url: https://github.com/OneUptime/oneuptime
author: Simon Larsen
author_date: 2024-03-22 10:28:33+00:00
msg: Add deletedByUserId property to several models
repository: repo_url: https://github.com/OneUptime/oneuptime
repo_name: OneUptime/oneuptime
description: OneUptime is the complete open-source observability platform.
repo_language: TypeScript
owner: OneUptime
file_changes: filename: ModelPermission.ts
change_type: ModificationType.MODIFY
diff: @@ -39,6 +39,7 @@ import UserType from 'Common/Types/UserType';
 import ColumnBillingAccessControl from 'Common/Types/BaseDatabase/ColumnBillingAccessControl';
 import DatabaseCommonInteractionPropsUtil from 'Common/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil';
 import Includes from 'Common/Types/BaseDatabase/Includes';
+import UserModel from 'Common/Models/UserModel';
 
 export interface CheckReadPermissionType<TBaseModel extends BaseModel> {
     query: Query<TBaseModel>;
@@ -295,6 +296,10 @@ export default class ModelPermission {
                 props
             );
 
+            // add user scope if any
+
+            query = await this.addUserScopeToQuery(modelType, query, props);
+
             if (!props.isMultiTenantRequest) {
                 // We will check for this permission in recursive function.
 
@@ -854,6 +859,26 @@ export default class ModelPermission {
         return query;
     }
 
+    private static async addUserScopeToQuery<TBaseModel extends BaseModel>(
+        modelType: { new (): TBaseModel },
+        query: Query<TBaseModel>,
+        props: DatabaseCommonInteractionProps
+    ): Promise<Query<TBaseModel>> {
+        const model: BaseModel = new modelType();
+
+        if (model instanceof UserModel) {
+            if (props.userId) {
+                (query as any)['_id'] = props.userId;
+            } else if (!props.isRoot && !props.isMasterAdmin) {
+                throw new NotAuthorizedException(
+                    `You do not have permissions to query on - ${model.singularName}.`
+                );
+            }
+        }
+
+        return query;
+    }
+
     private static async addTenantScopeToQuery<TBaseModel extends BaseModel>(
         modelType: { new (): TBaseModel },
         query: Query<TBaseModel>,

programming_language: TypeScript
filename: BillingInvoice.ts
change_type: ModificationType.MODIFY
diff: @@ -192,6 +192,7 @@ export default class BillingInvoice extends BaseModel {
     @JoinColumn({ name: 'deletedByUserId' })
     public deletedByUser?: User = undefined;
 
+
     @ColumnAccessControl({
         create: [],
         read: [

programming_language: TypeScript
filename: OnCallDutyPolicyEscalationRule.ts
change_type: ModificationType.MODIFY
diff: @@ -355,6 +355,25 @@ export default class OnCallDutyPolicyEscalationRule extends BaseModel {
     @JoinColumn({ name: 'deletedByUserId' })
     public deletedByUser?: User = undefined;
 
+    @ColumnAccessControl({
+        create: [],
+        read: [],
+        update: [],
+    })
+    @TableColumn({
+        type: TableColumnType.ObjectID,
+        title: 'Deleted by User ID',
+        description:
+            'User ID who deleted this object (if this object was deleted by a User)',
+    })
+    @Column({
+        type: ColumnType.ObjectID,
+        nullable: true,
+        transformer: ObjectID.getDatabaseTransformer(),
+    })
+    public deletedByUserId?: ObjectID = undefined;
+
+
     @ColumnAccessControl({
         create: [
             Permission.ProjectOwner,

programming_language: TypeScript
filename: OnCallDutyPolicyEscalationRuleSchedule.ts
change_type: ModificationType.MODIFY
diff: @@ -420,4 +420,23 @@ export default class OnCallDutyPolicyEscalationRuleSchedule extends BaseModel {
     )
     @JoinColumn({ name: 'deletedByUserId' })
     public deletedByUser?: User = undefined;
+
+
+    @ColumnAccessControl({
+        create: [],
+        read: [],
+        update: [],
+    })
+    @TableColumn({
+        type: TableColumnType.ObjectID,
+        title: 'Deleted by User ID',
+        description:
+            'User ID who deleted this object (if this object was deleted by a User)',
+    })
+    @Column({
+        type: ColumnType.ObjectID,
+        nullable: true,
+        transformer: ObjectID.getDatabaseTransformer(),
+    })
+    public deletedByUserId?: ObjectID = undefined;
 }

programming_language: TypeScript
filename: OnCallDutyPolicyEscalationRuleTeam.ts
change_type: ModificationType.MODIFY
diff: @@ -418,4 +418,22 @@ export default class OnCallDutyPolicyEscalationRuleTeam extends BaseModel {
     )
     @JoinColumn({ name: 'deletedByUserId' })
     public deletedByUser?: User = undefined;
+
+    @ColumnAccessControl({
+        create: [],
+        read: [],
+        update: [],
+    })
+    @TableColumn({
+        type: TableColumnType.ObjectID,
+        title: 'Deleted by User ID',
+        description:
+            'User ID who deleted this object (if this object was deleted by a User)',
+    })
+    @Column({
+        type: ColumnType.ObjectID,
+        nullable: true,
+        transformer: ObjectID.getDatabaseTransformer(),
+    })
+    public deletedByUserId?: ObjectID = undefined;
 }

programming_language: TypeScript
filename: OnCallDutyPolicyEscalationRuleUser.ts
change_type: ModificationType.MODIFY
diff: @@ -417,4 +417,22 @@ export default class OnCallDutyPolicyEscalationRuleUser extends BaseModel {
     )
     @JoinColumn({ name: 'deletedByUserId' })
     public deletedByUser?: User = undefined;
+
+    @ColumnAccessControl({
+        create: [],
+        read: [],
+        update: [],
+    })
+    @TableColumn({
+        type: TableColumnType.ObjectID,
+        title: 'Deleted by User ID',
+        description:
+            'User ID who deleted this object (if this object was deleted by a User)',
+    })
+    @Column({
+        type: ColumnType.ObjectID,
+        nullable: true,
+        transformer: ObjectID.getDatabaseTransformer(),
+    })
+    public deletedByUserId?: ObjectID = undefined;
 }

programming_language: TypeScript
filename: OnCallDutyPolicyExecutionLog.ts
change_type: ModificationType.MODIFY
diff: @@ -664,4 +664,6 @@ export default class OnCallDutyPolicyExecutionLog extends BaseModel {
         default: 1,
     })
     public onCallPolicyExecutionRepeatCount?: number = undefined;
+
+    
 }

programming_language: TypeScript
filename: OnCallDutyPolicyExecutionLogTimeline.ts
change_type: ModificationType.MODIFY
diff: @@ -708,4 +708,22 @@ export default class OnCallDutyPolicyExecutionLogTimeline extends BaseModel {
         unique: false,
     })
     public acknowledgedAt?: Date = undefined;
+
+    @ColumnAccessControl({
+        create: [],
+        read: [],
+        update: [],
+    })
+    @TableColumn({
+        type: TableColumnType.ObjectID,
+        title: 'Deleted by User ID',
+        description:
+            'User ID who deleted this object (if this object was deleted by a User)',
+    })
+    @Column({
+        type: ColumnType.ObjectID,
+        nullable: true,
+        transformer: ObjectID.getDatabaseTransformer(),
+    })
+    public deletedByUserId?: ObjectID = undefined;
 }

programming_language: TypeScript
filename: OnCallDutyPolicySchedule.ts
change_type: ModificationType.MODIFY
diff: @@ -402,4 +402,6 @@ export default class OnCallDutyPolicySchedule extends BaseModel {
         transformer: ObjectID.getDatabaseTransformer(),
     })
     public deletedByUserId?: ObjectID = undefined;
+
+    
 }

programming_language: TypeScript
filename: OnCallDutyPolicyScheduleLayer.ts
change_type: ModificationType.MODIFY
diff: @@ -556,4 +556,6 @@ export default class OnCallDutyPolicyScheduleLayer extends BaseModel {
         transformer: RestrictionTimes.getDatabaseTransformer(),
     })
     public restrictionTimes?: RestrictionTimes = undefined;
+
+    
 }

programming_language: TypeScript
filename: OnCallDutyPolicyScheduleLayerUser.ts
change_type: ModificationType.MODIFY
diff: @@ -494,4 +494,5 @@ export default class OnCallDutyPolicyScheduleLayerUser extends BaseModel {
         transformer: ObjectID.getDatabaseTransformer(),
     })
     public userId?: ObjectID = undefined;
+    
 }

programming_language: TypeScript
filename: User.ts
change_type: ModificationType.MODIFY
diff: @@ -32,11 +32,7 @@ import EnableDocumentation from 'Common/Types/Database/EnableDocumentation';
 @AllowAccessIfSubscriptionIsUnpaid()
 @TableAccessControl({
     create: [Permission.Public],
-    read: [
-        Permission.CurrentUser,
-        Permission.ProjectAdmin,
-        Permission.ProjectOwner,
-    ],
+    read: [Permission.CurrentUser],
     delete: [Permission.CurrentUser],
     update: [Permission.CurrentUser],
 })
@@ -56,11 +52,7 @@ import EnableDocumentation from 'Common/Types/Database/EnableDocumentation';
 class User extends UserModel {
     @ColumnAccessControl({
         create: [Permission.Public],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
         update: [Permission.CurrentUser],
     })
     @TableColumn({ type: TableColumnType.Name, canReadOnRelationQuery: true })
@@ -75,11 +67,7 @@ class User extends UserModel {
 
     @ColumnAccessControl({
         create: [Permission.Public],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
 
         update: [Permission.CurrentUser],
     })
@@ -247,11 +235,7 @@ class User extends UserModel {
 
     @ColumnAccessControl({
         create: [],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
 
         update: [Permission.CurrentUser],
     })
@@ -276,11 +260,7 @@ class User extends UserModel {
 
     @ColumnAccessControl({
         create: [],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
 
         update: [Permission.CurrentUser],
     })
@@ -297,11 +277,7 @@ class User extends UserModel {
 
     @ColumnAccessControl({
         create: [],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
 
         update: [Permission.CurrentUser],
     })
@@ -309,6 +285,7 @@ class User extends UserModel {
         isDefaultValueColumn: true,
         required: true,
         type: TableColumnType.Boolean,
+        canReadOnRelationQuery: true,
     })
     @Column({
         type: ColumnType.Boolean,
@@ -424,11 +401,7 @@ class User extends UserModel {
 
     @ColumnAccessControl({
         create: [],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
 
         update: [Permission.CurrentUser],
     })
@@ -543,11 +516,7 @@ class User extends UserModel {
 
     @ColumnAccessControl({
         create: [],
-        read: [
-            Permission.CurrentUser,
-            Permission.ProjectAdmin,
-            Permission.ProjectOwner,
-        ],
+        read: [Permission.CurrentUser],
 
         update: [Permission.CurrentUser],
     })

programming_language: TypeScript