From 2368c23cc48c5c9e5948dba301f25e3a4e556606 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 2 Aug 2026 17:46:17 +0000
Subject: [PATCH 1/2] feat: add Cloudflare Worker to inject HTTP security
headers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The site is hosted on GitHub Pages behind Cloudflare. GitHub Pages cannot
set custom HTTP response headers, so securityheaders.com gave the site an F.
This adds a Cloudflare Worker (cloudflare/worker.js) that attaches the six
missing security headers to every response:
- Strict-Transport-Security (HSTS, 1-year + preload)
- Content-Security-Policy (mirrors the existing HTML meta tag)
- X-Frame-Options (SAMEORIGIN)
- X-Content-Type-Options (nosniff)
- Referrer-Policy (strict-origin-when-cross-origin)
- Permissions-Policy (camera/mic/geo/payment/usb disabled)
A GitHub Actions workflow (.github/workflows/deploy-worker.yml) deploys the
worker automatically on every push to main that touches the cloudflare/
directory. Two repository secrets must be added to activate it:
CLOUDFLARE_API_TOKEN — a token with "Edit Workers" permission
CLOUDFLARE_ACCOUNT_ID — the Cloudflare account ID
Also removes the expired Chrome Prompt API origin-trial meta tag
(it expired 24 Mar 2026) from _layouts/default.html.
---
.github/workflows/deploy-worker.yml | 29 ++++++++++++++
_layouts/default.html | 3 --
cloudflare/worker.js | 59 +++++++++++++++++++++++++++++
cloudflare/wrangler.toml | 14 +++++++
4 files changed, 102 insertions(+), 3 deletions(-)
create mode 100644 .github/workflows/deploy-worker.yml
create mode 100644 cloudflare/worker.js
create mode 100644 cloudflare/wrangler.toml
diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml
new file mode 100644
index 0000000..e27c11c
--- /dev/null
+++ b/.github/workflows/deploy-worker.yml
@@ -0,0 +1,29 @@
+name: Deploy Cloudflare Worker (security headers)
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - "cloudflare/**"
+ workflow_dispatch:
+
+jobs:
+ deploy:
+ name: Deploy worker
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: cloudflare
+
+ steps:
+ # actions/checkout@v4
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+
+ # cloudflare/wrangler-action@v3
+ - name: Deploy with Wrangler
+ uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65
+ with:
+ apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ workingDirectory: cloudflare
diff --git a/_layouts/default.html b/_layouts/default.html
index 7f5ed97..592fa63 100644
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -14,9 +14,6 @@
-
-
-
diff --git a/cloudflare/worker.js b/cloudflare/worker.js
new file mode 100644
index 0000000..3a992d5
--- /dev/null
+++ b/cloudflare/worker.js
@@ -0,0 +1,59 @@
+/**
+ * Cloudflare Worker – adds HTTP security headers to every response.
+ *
+ * Deployed via .github/workflows/deploy-worker.yml.
+ * Required GitHub secrets:
+ * CLOUDFLARE_API_TOKEN – a token with "Edit Workers" permission
+ * CLOUDFLARE_ACCOUNT_ID – your Cloudflare account ID
+ */
+
+const SECURITY_HEADERS = {
+ // Enforce HTTPS for 1 year, include sub-domains, opt into the HSTS preload list
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
+
+ // Prevent browsers from MIME-sniffing away from the declared content-type
+ "X-Content-Type-Options": "nosniff",
+
+ // Allow framing only from the same origin (defence against clickjacking)
+ "X-Frame-Options": "SAMEORIGIN",
+
+ // Send only the origin (no path/query) for cross-origin requests
+ "Referrer-Policy": "strict-origin-when-cross-origin",
+
+ // Restrict access to powerful browser features that the site does not use
+ "Permissions-Policy":
+ "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()",
+
+ // Content Security Policy – mirrors the meta tag already in the HTML layout
+ // so that both HTTP-header CSP (enforced by the browser before HTML is parsed)
+ // and the meta tag (fallback) agree on the same policy.
+ "Content-Security-Policy": [
+ "default-src 'self'",
+ "script-src 'self' https://platform.twitter.com",
+ "style-src 'self' https://fonts.bunny.net",
+ "font-src https://fonts.bunny.net",
+ "img-src 'self' data: https://pbs.twimg.com https://abs.twimg.com",
+ "frame-src https://open.spotify.com https://platform.twitter.com",
+ "connect-src 'self' https://syndication.twitter.com",
+ "object-src 'none'",
+ "base-uri 'self'",
+ "form-action 'self'",
+ ].join("; "),
+};
+
+export default {
+ async fetch(request, _env, _ctx) {
+ const response = await fetch(request);
+
+ const newHeaders = new Headers(response.headers);
+ for (const [name, value] of Object.entries(SECURITY_HEADERS)) {
+ newHeaders.set(name, value);
+ }
+
+ return new Response(response.body, {
+ status: response.status,
+ statusText: response.statusText,
+ headers: newHeaders,
+ });
+ },
+};
diff --git a/cloudflare/wrangler.toml b/cloudflare/wrangler.toml
new file mode 100644
index 0000000..524e2ec
--- /dev/null
+++ b/cloudflare/wrangler.toml
@@ -0,0 +1,14 @@
+name = "remotehack-security-headers"
+main = "worker.js"
+compatibility_date = "2024-01-01"
+
+# The worker runs on the remotehack.space zone, intercepting every request
+# so it can attach security headers to every response before it reaches
+# the visitor's browser.
+#
+# account_id is supplied via the CLOUDFLARE_ACCOUNT_ID environment variable
+# in the GitHub Actions deployment workflow – do not hard-code it here.
+
+[[routes]]
+pattern = "remotehack.space/*"
+zone_name = "remotehack.space"
From f690f16464cf55f47a1e48cb2c02643b0a2e3fd3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 2 Aug 2026 17:47:53 +0000
Subject: [PATCH 2/2] fix: restrict GITHUB_TOKEN permissions in deploy-worker
workflow
---
.github/workflows/deploy-worker.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml
index e27c11c..b7af9d0 100644
--- a/.github/workflows/deploy-worker.yml
+++ b/.github/workflows/deploy-worker.yml
@@ -12,6 +12,8 @@ jobs:
deploy:
name: Deploy worker
runs-on: ubuntu-latest
+ permissions:
+ contents: read
defaults:
run:
working-directory: cloudflare