diff --git a/src/fastmcp/server/auth/oauth_proxy/ui.py b/src/fastmcp/server/auth/oauth_proxy/ui.py
index a8a12efe3..4ae6b5fb5 100644
--- a/src/fastmcp/server/auth/oauth_proxy/ui.py
+++ b/src/fastmcp/server/auth/oauth_proxy/ui.py
@@ -84,7 +84,7 @@ def create_consent_html(
detail_rows = [
("Application Name", html_module.escape(client_name or client_id)),
("Application Website", html_module.escape(client_website_url or "N/A")),
- ("Application ID", client_id),
+ ("Application ID", html_module.escape(client_id)),
("Redirect URI", redirect_uri_escaped),
(
"Requested Scopes",
diff --git a/tests/server/auth/oauth_proxy/test_ui.py b/tests/server/auth/oauth_proxy/test_ui.py
index 4795ec2ff..6f174aec2 100644
--- a/tests/server/auth/oauth_proxy/test_ui.py
+++ b/tests/server/auth/oauth_proxy/test_ui.py
@@ -7,7 +7,7 @@ from starlette.requests import Request
from starlette.responses import HTMLResponse
from fastmcp.server.auth.oauth_proxy import OAuthProxy
-from fastmcp.server.auth.oauth_proxy.ui import create_error_html
+from fastmcp.server.auth.oauth_proxy.ui import create_consent_html, create_error_html
from fastmcp.server.auth.providers.jwt import JWTVerifier
@@ -99,3 +99,21 @@ class TestErrorPageRendering:
assert b"invalid_scope" in response.body
assert b"doesn't exist" in response.body # HTML-escaped apostrophe
assert b"OAuth Error" in response.body
+
+
+class TestConsentPageRendering:
+ """Test consent page rendering and escaping."""
+
+ def test_create_consent_html_escapes_client_id_in_details(self):
+ """Test that Application ID is escaped in advanced details."""
+
+ html = create_consent_html(
+ client_id='evil
',
+ redirect_uri="https://example.com/callback",
+ scopes=["read"],
+ txn_id="txn",
+ csrf_token="csrf",
+ )
+
+ assert 'evil
' not in html
+ assert "evil<img src=x onerror=alert("xss")>" in html