CVE-2023-52077 (published 2023-12-27T19:15Z)

Nexkey is a lightweight fork of Misskey v12 optimized for small to medium size servers. Prior to 12.23Q4.5, Nexkey allows external apps using tokens issued by administrators and moderators to call admin APIs.  This allows malicious third-party apps to perform operations such as updating server settings, as well as compromise object storage and email server credentials. This issue has been patched in 12.23Q4.5.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-863
cwe_name: Incorrect Authorization
description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are incorrectly applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/mei23/misskey-v12
commit_details: repo_url: https://github.com/mei23/misskey-v12
author: mei23
author_date: 2023-12-27 01:30:47+09:00
msg: Appは管理者/モデレータ権限を使えないように v12 latest
repository: repo_url: https://github.com/mei23/misskey-v12
repo_name: mei23/misskey-v12
repo_language: TypeScript
owner: mei23
file_changes: filename: call.ts
change_type: ModificationType.MODIFY
diff: @@ -93,6 +93,14 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
 		});
 	}
 
+	if (token && ep.meta.requireAdmin) {
+		throw new ApiError(accessDenied, { reason: 'Apps cannot use admin privileges.' });
+	}
+
+	if (token && ep.meta.requireModerator) {
+		throw new ApiError(accessDenied, { reason: 'Apps cannot use moderator privileges.' });
+	}
+
 	// Cast non JSON input
 	if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) {
 		for (const k of Object.keys(ep.params.properties)) {

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -29,12 +29,13 @@ export const paramDef = {
 } as const;
 
 // eslint-disable-next-line import/no-default-export
-export default define(meta, paramDef, async (ps, _me) => {
+export default define(meta, paramDef, async (ps, _me, token) => {
 	const me = _me ? await Users.findOneByOrFail({ id: _me.id }) : null;
 	const noUsers = (await Users.countBy({
 		host: IsNull(),
 	})) === 0;
 	if (!noUsers && !me?.isAdmin) throw new Error('access denied');
+	if (token) throw new Error('access denied');
 
 	const { account, secret } = await signup({
 		username: ps.username,

programming_language: TypeScript
repo_url: https://github.com/misskey-dev/misskey
commit_details: repo_url: https://github.com/misskey-dev/misskey
author: syuilo
author_date: 2023-12-18 12:32:26+09:00
msg: fix(backend): add missing kind definition for admin endpoints to improve security
repository: repo_url: https://github.com/misskey-dev/misskey
repo_name: misskey-dev/misskey
description: 🌎 An interplanetary microblogging platform 🚀
repo_language: TypeScript
owner: misskey-dev
file_changes: filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -93,6 +93,7 @@
 - Fix: アカウントをブロックした際に、自身のユーザーのページでノートが相手に表示される問題を修正
 - Fix: モデレーションログがモデレーターは閲覧できないように修正
 - Fix: HTTP Digestヘッダのアルゴリズム部分に大文字の"SHA-256"しか使えない
+- Fix: 管理者用APIのアクセス権限が適切に設定されていない問題を修正
 
 ## 2023.11.1
 

programming_language: Markdown
filename: abuse-user-reports.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { AbuseUserReportEntityService } from '@/core/entities/AbuseUserReportEnt
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -15,6 +15,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	res: {
 		type: 'object',
 		optional: false, nullable: false,

programming_language: TypeScript
filename: delete.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 } as const;

programming_language: TypeScript
filename: find-by-email.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '@/server/api/error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: delete.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: update.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { AnnouncementService } from '@/core/AnnouncementService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: delete.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { IdService } from '@/core/IdService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: update.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageAvatarDecorations',
 } as const;

programming_language: TypeScript
filename: delete.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageAvatarDecorations',
 	errors: {

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -15,6 +15,8 @@ import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageAvatarDecorations',
 

programming_language: TypeScript
filename: update.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageAvatarDecorations',
 

programming_language: TypeScript
filename: delete-account.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: delete-all-files-of-a-user.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 } as const;

programming_language: TypeScript
filename: clean-remote-files.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { QueueService } from '@/core/QueueService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: cleanup.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: files.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: show-file.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: add-aliases-bulk.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: add.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 

programming_language: TypeScript
filename: copy.ts
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 

programming_language: TypeScript
filename: delete-bulk.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: delete.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 

programming_language: TypeScript
filename: import-zip.ts
change_type: ModificationType.MODIFY
diff: @@ -8,7 +8,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
 import { QueueService } from '@/core/QueueService.js';
 
 export const meta = {
-	secure: true,
+	kind: 'write:admin',
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: list-remote.ts
change_type: ModificationType.MODIFY
diff: @@ -15,6 +15,8 @@ import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -15,6 +15,8 @@ import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 

programming_language: TypeScript
filename: remove-aliases-bulk.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: set-aliases-bulk.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: set-category-bulk.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: set-license-bulk.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 } as const;

programming_language: TypeScript
filename: update.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireRolePolicy: 'canManageCustomEmojis',
 

programming_language: TypeScript
filename: delete-all-files.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: refresh-remote-instance-metadata.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: remove-all-following.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { QueueService } from '@/core/QueueService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: update-instance.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: get-index-stats.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ export const meta = {
 	requireCredential: true,
 	requireAdmin: true,
 
+	kind: 'read:admin',
+
 	tags: ['admin'],
 } as const;
 

programming_language: TypeScript
filename: get-table-stats.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ export const meta = {
 	requireCredential: true,
 	requireAdmin: true,
 
+	kind: 'read:admin',
+
 	tags: ['admin'],
 
 	res: {

programming_language: TypeScript
filename: get-user-ips.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { IdService } from '@/core/IdService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: meta.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { DEFAULT_POLICIES } from '@/core/RoleService.js';
 export const meta = {
 	tags: ['meta'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: clear.ts
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@ import { QueueService } from '@/core/QueueService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: deliver-delayed.ts
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@ import type { DeliverQueue } from '@/core/QueueModule.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: inbox-delayed.ts
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@ import type { InboxQueue } from '@/core/QueueModule.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: promote.ts
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@ import { QueueService } from '@/core/QueueService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: stats.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: add.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { RelayService } from '@/core/RelayService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: remove.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { RelayService } from '@/core/RelayService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: reset-password.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: resolve-abuse-user-report.ts
change_type: ModificationType.MODIFY
diff: @@ -15,6 +15,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: assign.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { RoleService } from '@/core/RoleService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: create.ts
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@ import { RoleService } from '@/core/RoleService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: delete.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { RoleService } from '@/core/RoleService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: list.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { RoleEntityService } from '@/core/entities/RoleEntityService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: show.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { RoleEntityService } from '@/core/entities/RoleEntityService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'read:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: unassign.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { RoleService } from '@/core/RoleService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 

programming_language: TypeScript
filename: update-default-policies.ts
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@ import { MetaService } from '@/core/MetaService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 } as const;

programming_language: TypeScript
filename: update.ts
change_type: ModificationType.MODIFY
diff: @@ -14,6 +14,8 @@ import { RoleService } from '@/core/RoleService.js';
 export const meta = {
 	tags: ['admin', 'role'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: users.ts
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,8 @@ import { ApiError } from '../../../error.js';
 export const meta = {
 	tags: ['admin', 'role', 'users'],
 
+	kind: 'read:admin',
+
 	requireCredential: false,
 	requireAdmin: true,
 

programming_language: TypeScript
filename: send-email.ts
change_type: ModificationType.MODIFY
diff: @@ -10,6 +10,8 @@ import { EmailService } from '@/core/EmailService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: server-info.ts
change_type: ModificationType.MODIFY
diff: @@ -17,6 +17,8 @@ export const meta = {
 
 	tags: ['admin', 'meta'],
 
+	kind: 'read:admin',
+
 	res: {
 		type: 'object',
 		optional: false, nullable: false,

programming_language: TypeScript
filename: show-moderation-logs.ts
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,8 @@ export const meta = {
 	requireCredential: true,
 	requireAdmin: true,
 
+	kind: 'read:admin',
+
 	res: {
 		type: 'array',
 		optional: false, nullable: false,

programming_language: TypeScript
filename: show-user.ts
change_type: ModificationType.MODIFY
diff: @@ -17,6 +17,8 @@ export const meta = {
 	requireCredential: true,
 	requireModerator: true,
 
+	kind: 'read:admin',
+
 	res: {
 		type: 'object',
 		nullable: false, optional: false,

programming_language: TypeScript
filename: show-users.ts
change_type: ModificationType.MODIFY
diff: @@ -17,6 +17,8 @@ export const meta = {
 	requireCredential: true,
 	requireModerator: true,
 
+	kind: 'read:admin',
+
 	res: {
 		type: 'array',
 		nullable: false, optional: false,

programming_language: TypeScript
filename: suspend-user.ts
change_type: ModificationType.MODIFY
diff: @@ -19,6 +19,8 @@ import { QueueService } from '@/core/QueueService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: unset-user-avatar.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;
@@ -39,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			if (user == null) {
 				throw new Error('user not found');
 			}
-	
+
 			if (user.avatarId == null) return;
 
 			await this.usersRepository.update(user.id, {

programming_language: TypeScript
filename: unset-user-banner.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: unsuspend-user.ts
change_type: ModificationType.MODIFY
diff: @@ -13,6 +13,8 @@ import { DI } from '@/di-symbols.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
filename: update-meta.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { MetaService } from '@/core/MetaService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireAdmin: true,
 } as const;

programming_language: TypeScript
filename: update-user-note.ts
change_type: ModificationType.MODIFY
diff: @@ -12,6 +12,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
 export const meta = {
 	tags: ['admin'],
 
+	kind: 'write:admin',
+
 	requireCredential: true,
 	requireModerator: true,
 } as const;

programming_language: TypeScript
repo_url: https://github.com/nexryai/nexkey
commit_details: repo_url: https://github.com/nexryai/nexkey
author: nexryai
author_date: 2023-12-27 08:05:05+09:00
msg: Security: Appは管理者/モデレータ権限を使えないように
repository: repo_url: https://github.com/nexryai/nexkey
repo_name: nexryai/nexkey
description: nexryaiによるMisskey v12フォーク
repo_language: TypeScript
owner: nexryai
file_changes: filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,7 @@
 ## 12.23Q4.5
  - Security Hotfix: 管理者用APIのアクセス権限が適切に設定されていない問題を修正
  - fix: Filter featured collection
+ - Appは管理者/モデレータ権限を使えないように
  - 依存関係の更新
 
 ## 12.23Q4.4

programming_language: Markdown
filename: call.ts
change_type: ModificationType.MODIFY
diff: @@ -93,6 +93,14 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
         });
     }
 
+    if (token && ep.meta.requireAdmin) {
+        throw new ApiError(accessDenied, { reason: "Apps cannot use admin privileges." });
+    }
+
+    if (token && ep.meta.requireModerator) {
+        throw new ApiError(accessDenied, { reason: "Apps cannot use moderator privileges." });
+    }
+
     // Cast non JSON input
     if ((ep.meta.requireFile || ctx?.method === "GET") && ep.params.properties) {
         for (const k of Object.keys(ep.params.properties)) {

programming_language: TypeScript