diff --git a/doc/guide/embedding.xml b/doc/guide/embedding.xml
index 99b30dcebd2c..7fe8aa962ac1 100644
--- a/doc/guide/embedding.xml
+++ b/doc/guide/embedding.xml
@@ -5,7 +5,9 @@
Embedding and Integrating Cockpit
Cockpit can be embedded in other web applications either as a whole or specific
- Cockpit components can be integrated.
+ Cockpit components can be integrated. Due to frame security policy restrictions,
+ this only works if Cockpit and the web application have the same origin;
+ this is commonly achieved by running both from a common reverse proxy.
Embedding the Cockpit Interface
diff --git a/pkg/base1/test-http.js b/pkg/base1/test-http.js
index 9d38abcb8a77..6d86a8f33356 100644
--- a/pkg/base1/test-http.js
+++ b/pkg/base1/test-http.js
@@ -208,6 +208,7 @@ QUnit.test("headers", function (assert) {
"Referrer-Policy": "no-referrer",
"X-DNS-Prefetch-Control": "off",
"X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "sameorigin",
"Cross-Origin-Resource-Policy": "same-origin",
}, "got back headers");
})
@@ -250,6 +251,7 @@ QUnit.test("connection headers", function (assert) {
"Referrer-Policy": "no-referrer",
"X-DNS-Prefetch-Control": "off",
"X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "sameorigin",
"Cross-Origin-Resource-Policy": "same-origin",
}, "got back combined headers");
})
diff --git a/src/bridge/test-httpstream.c b/src/bridge/test-httpstream.c
index d6aabc968705..274fe0776035 100644
--- a/src/bridge/test-httpstream.c
+++ b/src/bridge/test-httpstream.c
@@ -34,7 +34,7 @@
extern gboolean cockpit_webserver_want_certificate;
/* JSON dict snippet for headers that are present in every request */
-#define STATIC_HEADERS "\"Cross-Origin-Resource-Policy\":\"same-origin\",\"Referrer-Policy\":\"no-referrer\",\"X-Content-Type-Options\":\"nosniff\",\"X-DNS-Prefetch-Control\":\"off\""
+#define STATIC_HEADERS "\"Cross-Origin-Resource-Policy\":\"same-origin\",\"Referrer-Policy\":\"no-referrer\",\"X-Content-Type-Options\":\"nosniff\",\"X-DNS-Prefetch-Control\":\"off\",\"X-Frame-Options\":\"sameorigin\""
static void
on_closed_set_flag (CockpitChannel *channel,
diff --git a/src/bridge/test-packages.c b/src/bridge/test-packages.c
index 8c90f936063f..b11a8c8341ce 100644
--- a/src/bridge/test-packages.c
+++ b/src/bridge/test-packages.c
@@ -47,7 +47,7 @@
#define CHECKSUM_CSP "80921dc3cde9ff9f2acd2a5851f9b2a3b25ea7b4577128461d9e32fbdd671e16"
/* JSON dict snippet for headers that are present in every request */
-#define STATIC_HEADERS "\"X-DNS-Prefetch-Control\":\"off\",\"Referrer-Policy\":\"no-referrer\",\"X-Content-Type-Options\":\"nosniff\",\"Cross-Origin-Resource-Policy\": \"same-origin\""
+#define STATIC_HEADERS "\"X-DNS-Prefetch-Control\":\"off\",\"Referrer-Policy\":\"no-referrer\",\"X-Content-Type-Options\":\"nosniff\",\"Cross-Origin-Resource-Policy\": \"same-origin\",\"X-Frame-Options\": \"sameorigin\""
#define STATIC_HEADERS_CACHECONTROL STATIC_HEADERS ",\"Cache-Control\":\"no-cache, no-store\""
extern const gchar **cockpit_bridge_data_dirs;
diff --git a/src/common/cockpitwebresponse.c b/src/common/cockpitwebresponse.c
index fb09d22a6957..671f1c50821f 100644
--- a/src/common/cockpitwebresponse.c
+++ b/src/common/cockpitwebresponse.c
@@ -747,6 +747,7 @@ enum {
HEADER_REFERRER_POLICY = 1 << 5,
HEADER_CONTENT_TYPE_OPTIONS = 1 << 6,
HEADER_CROSS_ORIGIN_RESOURCE_POLICY = 1 << 7,
+ HEADER_X_FRAME_OPTIONS = 1 << 8,
};
static GString *
@@ -789,6 +790,8 @@ append_header (GString *string,
return HEADER_CONTENT_TYPE_OPTIONS;
if (g_ascii_strcasecmp ("Cross-Origin-Resource-Policy", name) == 0)
return HEADER_CROSS_ORIGIN_RESOURCE_POLICY;
+ if (g_ascii_strcasecmp ("X-Frame-Options", name) == 0)
+ return HEADER_X_FRAME_OPTIONS;
if (g_ascii_strcasecmp ("Content-Length", name) == 0 ||
g_ascii_strcasecmp ("Transfer-Encoding", name) == 0 ||
g_ascii_strcasecmp ("Connection", name) == 0)
@@ -900,6 +903,9 @@ finish_headers (CockpitWebResponse *self,
* be able to read any resource. This does *not* affect embedding with