diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index a84feffac6..d06bb2d8df 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -31,6 +31,7 @@ import { IdService } from '@/core/IdService.js';
 import { MetaService } from '../MetaService.js';
 import { LdSignatureService } from './LdSignatureService.js';
 import { ApMfmService } from './ApMfmService.js';
+import { CONTEXT } from './misc/contexts.js';
 import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
 
 @Injectable()
@@ -785,48 +786,7 @@ export class ApRendererService {
 			x.id = `${this.config.url}/${randomUUID()}`;
 		}
 
-		return Object.assign({
-			'@context': [
-				'https://www.w3.org/ns/activitystreams',
-				'https://w3id.org/security/v1',
-				{
-					Key: 'sec:Key',
-					// as non-standards
-					manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
-					sensitive: 'as:sensitive',
-					Hashtag: 'as:Hashtag',
-					quoteUrl: 'as:quoteUrl',
-					fedibird: 'http://fedibird.com/ns#',
-					quoteUri: 'fedibird:quoteUri',
-					// Mastodon
-					toot: 'http://joinmastodon.org/ns#',
-					Emoji: 'toot:Emoji',
-					featured: 'toot:featured',
-					discoverable: 'toot:discoverable',
-					// schema
-					schema: 'http://schema.org#',
-					PropertyValue: 'schema:PropertyValue',
-					value: 'schema:value',
-					// Misskey
-					misskey: 'https://misskey-hub.net/ns#',
-					'_misskey_content': 'misskey:_misskey_content',
-					'_misskey_quote': 'misskey:_misskey_quote',
-					'_misskey_reaction': 'misskey:_misskey_reaction',
-					'_misskey_votes': 'misskey:_misskey_votes',
-					'_misskey_summary': 'misskey:_misskey_summary',
-					'isCat': 'misskey:isCat',
-					// Firefish
-					firefish: 'https://joinfirefish.org/ns#',
-					speakAsCat: 'firefish:speakAsCat',
-					// Sharkey
-					sharkey: 'https://joinsharkey.org/ns#',
-					backgroundUrl: 'sharkey:backgroundUrl',
-					listenbrainz: 'sharkey:listenbrainz',
-					// vcard
-					vcard: 'http://www.w3.org/2006/vcard/ns#',
-				},
-			],
-		}, x as T & { id: string });
+		return Object.assign({ '@context': CONTEXT }, x as T & { id: string });
 	}
 
 	@bindThis
diff --git a/packages/backend/src/core/activitypub/LdSignatureService.ts b/packages/backend/src/core/activitypub/LdSignatureService.ts
index 9de184336f..2ec6dc4585 100644
--- a/packages/backend/src/core/activitypub/LdSignatureService.ts
+++ b/packages/backend/src/core/activitypub/LdSignatureService.ts
@@ -7,7 +7,7 @@ import * as crypto from 'node:crypto';
 import { Injectable } from '@nestjs/common';
 import { HttpRequestService } from '@/core/HttpRequestService.js';
 import { bindThis } from '@/decorators.js';
-import { CONTEXTS } from './misc/contexts.js';
+import { CONTEXT, CONTEXTS } from './misc/contexts.js';
 import { validateContentTypeSetAsJsonLD } from './misc/validator.js';
 import type { JsonLdDocument } from 'jsonld';
 import type { JsonLd, RemoteDocument } from 'jsonld/jsonld-spec.js';
@@ -88,6 +88,16 @@ class LdSignature {
 		return verifyData;
 	}
 
+	@bindThis
+	public async compact(data: any, context: any = CONTEXT): Promise<JsonLdDocument> {
+		const customLoader = this.getLoader();
+		// XXX: Importing jsonld dynamically since Jest frequently fails to import it statically
+		// https://github.com/misskey-dev/misskey/pull/9894#discussion_r1103753595
+		return (await import('jsonld')).default.compact(data, context, {
+			documentLoader: customLoader,
+		});
+	}
+
 	@bindThis
 	public async normalize(data: JsonLdDocument): Promise<string> {
 		const customLoader = this.getLoader();
diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts
index 88afdefcd3..4ff114bbf5 100644
--- a/packages/backend/src/core/activitypub/misc/contexts.ts
+++ b/packages/backend/src/core/activitypub/misc/contexts.ts
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import type { JsonLd } from 'jsonld/jsonld-spec.js';
+import type { Context, JsonLd } from 'jsonld/jsonld-spec.js';
 
 /* eslint:disable:quotemark indent */
 const id_v1 = {
@@ -526,6 +526,50 @@ const activitystreams = {
 	},
 } satisfies JsonLd;
 
+const context_iris = [
+	'https://www.w3.org/ns/activitystreams',
+	'https://w3id.org/security/v1',
+];
+
+const extension_context_definition = {
+	Key: 'sec:Key',
+	// as non-standards
+	manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
+	sensitive: 'as:sensitive',
+	Hashtag: 'as:Hashtag',
+	quoteUrl: 'as:quoteUrl',
+	fedibird: 'http://fedibird.com/ns#',
+	quoteUri: 'fedibird:quoteUri',
+	// Mastodon
+	toot: 'http://joinmastodon.org/ns#',
+	Emoji: 'toot:Emoji',
+	featured: 'toot:featured',
+	discoverable: 'toot:discoverable',
+	// schema
+	schema: 'http://schema.org#',
+	PropertyValue: 'schema:PropertyValue',
+	value: 'schema:value',
+	// Misskey
+	misskey: 'https://misskey-hub.net/ns#',
+	'_misskey_content': 'misskey:_misskey_content',
+	'_misskey_quote': 'misskey:_misskey_quote',
+	'_misskey_reaction': 'misskey:_misskey_reaction',
+	'_misskey_votes': 'misskey:_misskey_votes',
+	'_misskey_summary': 'misskey:_misskey_summary',
+	'isCat': 'misskey:isCat',
+	// Firefish
+	firefish: 'https://joinfirefish.org/ns#',
+	speakAsCat: 'firefish:speakAsCat',
+	// Sharkey
+	sharkey: 'https://joinsharkey.org/ns#',
+	backgroundUrl: 'sharkey:backgroundUrl',
+	listenbrainz: 'sharkey:listenbrainz',
+	// vcard
+	vcard: 'http://www.w3.org/2006/vcard/ns#',
+} satisfies Context;
+
+export const CONTEXT: (string | Context)[] = [...context_iris, extension_context_definition];
+
 export const CONTEXTS: Record<string, JsonLd> = {
 	'https://w3id.org/identity/v1': id_v1,
 	'https://w3id.org/security/v1': security_v1,
diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts
index ad1d9799a7..2b5b7c5619 100644
--- a/packages/backend/src/queue/processors/InboxProcessorService.ts
+++ b/packages/backend/src/queue/processors/InboxProcessorService.ts
@@ -15,6 +15,7 @@ import InstanceChart from '@/core/chart/charts/instance.js';
 import ApRequestChart from '@/core/chart/charts/ap-request.js';
 import FederationChart from '@/core/chart/charts/federation.js';
 import { getApId } from '@/core/activitypub/type.js';
+import type { IActivity } from '@/core/activitypub/type.js';
 import type { MiRemoteUser } from '@/models/User.js';
 import type { MiUserPublickey } from '@/models/UserPublickey.js';
 import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
@@ -52,7 +53,7 @@ export class InboxProcessorService {
 	@bindThis
 	public async process(job: Bull.Job<InboxJobData>): Promise<string> {
 		const signature = job.data.signature;	// HTTP-signature
-		const activity = job.data.activity;
+		let activity = job.data.activity;
 
 		//#region Log
 		const info = Object.assign({}, activity);
@@ -150,6 +151,17 @@ export class InboxProcessorService {
 					throw new Bull.UnrecoverableError('skip: LD-Signatureの検証に失敗しました');
 				}
 
+				// アクティビティを正規化
+				delete activity.signature;
+				try {
+					activity = await ldSignature.compact(activity) as IActivity;
+				} catch (e) {
+					throw new Bull.UnrecoverableError(`skip: failed to compact activity: ${e}`);
+				}
+				// TODO: 元のアクティビティと非互換な形に正規化される場合は転送をスキップする
+				// https://github.com/mastodon/mastodon/blob/664b0ca/app/services/activitypub/process_collection_service.rb#L24-L29
+				activity.signature = ldSignature;
+
 				// もう一度actorチェック
 				if (authUser.user.uri !== activity.actor) {
 					throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`);