diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6216ecf43..8529b2c522 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2025.2.0-yumechinokuni.1
+
+- Security: Revert miskey-dev/misskey#14897
+- Security: AP請求を外部ドメーンにリダイレクトしないように
+
 ## 2025.2.0
 
 ### General
@@ -208,12 +213,6 @@ PgroongaのCWサーチ (github.com/paricafe/misskey#d30db97b59d264450901c1dd8680
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/712)
 - Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正  
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709)
-- Fix: User Webhookテスト機能のMock Payloadを修正  
-- Fix: アカウント削除のモデレーションログが動作していないのを修正 (#14996)  
-- Fix: リノートミュートが新規投稿通知に対して作用していなかった問題を修正
-- Fix: Inboxの処理で生じるエラーを誤ってActivityとして処理することがある問題を修正  
-  (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/730)
-- Fix: セキュリティに関する修正
 
 ### Misskey.js
 - Fix: Stream初期化時、別途WebSocketを指定する場合の型定義を修正
diff --git a/package.json b/package.json
index 0984b0cc1a..76459b8c75 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "2025.2.0-yumechinokuni.0",
+	"version": "2025.2.0-yumechinokuni.1",
 	"codename": "nasubi",
 	"repository": {
 		"type": "git",
diff --git a/packages/backend/src/core/activitypub/misc/check-against-url.ts b/packages/backend/src/core/activitypub/misc/check-against-url.ts
index 5610cfdeb8..ceb1caf6ee 100644
--- a/packages/backend/src/core/activitypub/misc/check-against-url.ts
+++ b/packages/backend/src/core/activitypub/misc/check-against-url.ts
@@ -17,16 +17,16 @@ function getHrefFrom(one: IObject|string): string | undefined {
 }
 
 export function assertActivityMatchesUrls(activity: IObject, urls: string[]) {
-	const idBad = activity.id !== undefined && !urls.includes(activity.id);
+	let idBad = activity.id !== undefined && !urls.includes(activity.id);
 
 	// technically `activity.url` could be an `ApObject = IObject |
 	// string | (IObject | string)[]`, but if it's a complicated thing
 	// and the `activity.id` doesn't match, I think we're fine
 	// rejecting the activity
-	const urlBad = typeof activity.url === 'string' && !urls.includes(activity.url);
+	const urlBad = activity.url != undefined && (typeof activity.url !== 'string' || !urls.includes(activity.url));
 
+	// both of them have to pass checks, if present
 	if (idBad || urlBad) {
-
 		const hosts = urls.map(u => {
 			try {
 				return new URL(u).host;
@@ -42,6 +42,7 @@ export function assertActivityMatchesUrls(activity: IObject, urls: string[]) {
 		throw new Error(`bad Activity: neither id(${activity?.id}) nor url(${JSON.stringify(activity?.url)}) match location(${urls})`);
 	}
 
+	// at least one of the key field must be present
 	if (activity.id || activity.url) {
 		return;
 	}
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index 8c4b13a40a..71a69d4c33 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -29,7 +29,6 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
 import { bindThis } from '@/decorators.js';
 import { IActivity } from '@/core/activitypub/type.js';
 import { isQuote, isRenote } from '@/misc/is-renote.js';
-import * as Acct from '@/misc/acct.js';
 import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
 import type { FindOptionsWhere } from 'typeorm';
 
@@ -487,16 +486,6 @@ export class ActivityPubServerService {
 			return;
 		}
 
-		// リモートだったらリダイレクト
-		if (user.host != null) {
-			if (user.uri == null || this.utilityService.isSelfHost(user.host)) {
-				reply.code(500);
-				return;
-			}
-			reply.redirect(user.uri, 301);
-			return;
-		}
-
 		reply.header('Cache-Control', 'public, max-age=180');
 		this.setResponseType(request, reply);
 		return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as MiLocalUser)));
@@ -665,20 +654,19 @@ export class ActivityPubServerService {
 
 			const user = await this.usersRepository.findOneBy({
 				id: userId,
+				host: IsNull(),
 				isSuspended: false,
 			});
 
 			return await this.userInfo(request, reply, user);
 		});
 
-		fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
+		fastify.get<{ Params: { user: string; } }>('/@:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
 			vary(reply.raw, 'Accept');
 
-			const acct = Acct.parse(request.params.acct);
-
 			const user = await this.usersRepository.findOneBy({
-				usernameLower: acct.username,
-				host: acct.host ?? IsNull(),
+				usernameLower: request.params.user.toLowerCase(),
+				host: IsNull(),
 				isSuspended: false,
 			});
 
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index 818efd8740..d1b8e9e05a 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -290,6 +290,35 @@ export class ServerService implements OnApplicationShutdown {
 			done();
 		});
 
+		fastify.addHook('onSend', (request, reply, payload, done) => {
+			if (reply.statusCode >= 300 && reply.statusCode < 400) {
+				const isAp = ["application/activity+json", "application/ld+json"].some(type => request.headers.accept?.includes(type));
+			
+				if (isAp) {
+					const location = reply.getHeader('location');
+
+					// the only acceptable redirect is to our own domain
+					if (typeof location === 'string') {
+						// allow http in development
+						const normalizedLocation = process.env.NODE_ENV !== 'production' ?
+							location.replace(/^http:\/\//, 'https://') : location;
+
+						if ([`https://${this.config.host}/`, `https://${this.config.hostname}/`].some(host => normalizedLocation.startsWith(host))) {
+							done(null, payload);
+							return;
+						}
+					}
+					
+					reply.code(406);
+					reply.removeHeader('location');
+					done(null, null);
+					return;
+				}
+			}
+			
+			done(null, payload);
+		});
+
 		// CSP
 		if (process.env.NODE_ENV === 'production' && !this.config.browserSandboxing.csp?.disable) {
 			console.debug('cspPrerenderedContent', this.config.cspPrerenderedContent);
diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts
index 8ea4cb9800..7efd688ec2 100644
--- a/packages/backend/test/e2e/fetch-resource.ts
+++ b/packages/backend/test/e2e/fetch-resource.ts
@@ -230,7 +230,6 @@ describe('Webリソース', () => {
 				path: path('xxxxxxxxxx'),
 				type: HTML,
 			}));
-			test.todo('HTMLとしてGETできる。(リモートユーザーでもリダイレクトせず)');
 		});
 
 		describe.each([
@@ -250,7 +249,6 @@ describe('Webリソース', () => {
 				path: path('xxxxxxxxxx'),
 				accept,
 			}));
-			test.todo('はオリジナルにリダイレクトされる。(リモートユーザー)');
 		});
 	});
 
diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json
index ceccbcd532..ae59679912 100644
--- a/packages/misskey-js/package.json
+++ b/packages/misskey-js/package.json
@@ -1,7 +1,7 @@
 {
 	"type": "module",
 	"name": "misskey-js",
-	"version": "2025.2.0-yumechinokuni.0",
+	"version": "2025.2.0-yumechinokuni.1",
 	"description": "Misskey SDK for JavaScript",
 	"license": "MIT",
 	"main": "./built/index.js",