Skip to content

#610 Add frame-ancestors 'self' to the content security policy - #642

Merged
ajs-uk-dev merged 3 commits into
mainfrom
feature/610-frame_ancestors
Oct 19, 2026
Merged

ajs-uk-dev merged 3 commits into
mainfrom
feature/610-frame_ancestors

Conversation

@ajs-uk-dev

Copy link
Copy Markdown
Contributor

Closes #610 (part of the OWASP set #607).

frame-ancestors is the CSP directive that decides which sites may put the service in a frame; it replaced X-Frame-Options in current browsers. The policy had no such directive, and the app has never set X-Frame-Options — the middleware's remark said it did, and that is corrected here — so whether a page could be framed depended on whatever sat in front of the app.

  • frame-ancestors 'self' joins ContentSecurityPolicyBase in SecurityHeadersMiddleware; nothing else in the policy changes ('unsafe-inline' / 'unsafe-eval' are Remove 'unsafe-inline' and 'unsafe-eval' from the CSP script-src #611).
  • SecurityHeadersMiddlewareTests.FrameAncestors_AllowsOnlyThisSite asserts the whole directive, not a substring.
  • The class remark and the test file's header no longer claim X-Frame-Options.
  • The technical overview lists the directive.

Tested: unit 7,479 / 0 (7,478 on main), build 0 errors. Review-app proof in a comment below.

🤖 Generated with Claude Code

Andy Smith and others added 2 commits October 19, 2026 14:40
frame-ancestors 'self' joins the policy base. The app never set
X-Frame-Options, so the class remark and the test header that said it
did are corrected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review app for PR 642 was deleted

@ajs-uk-dev

Copy link
Copy Markdown
Contributor Author

Review-app proof at ce31ba7:

$ curl -sI https://check-performance-data-pr-642.test.teacherservices.cloud/ | grep -iE "^(content-security-policy|x-frame-options):"
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://*.clarity.ms; style-src 'self' 'unsafe-inline' https://*.googletagmanager.com https://fonts.googleapis.com; img-src 'self' data: blob: https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://*.clarity.ms https://fonts.gstatic.com; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://*.clarity.ms; frame-src 'self' https://*.googletagmanager.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self' https://test-oidc.signin.education.gov.uk
X-Frame-Options: SAMEORIGIN

$ curl -sI https://check-performance-data-pr-642.test.teacherservices.cloud/robots.txt | grep -iE "^(content-security-policy|x-frame-options):"
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://*.clarity.ms; style-src 'self' 'unsafe-inline' https://*.googletagmanager.com https://fonts.googleapis.com; img-src 'self' data: blob: https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://*.clarity.ms https://fonts.gstatic.com; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://*.clarity.ms; frame-src 'self' https://*.googletagmanager.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self' https://test-oidc.signin.education.gov.uk

frame-ancestors 'self' is on the start page and on /robots.txt, and form-action is still the last directive.

X-Frame-Options: SAMEORIGIN appears on the start page only, not on /robots.txt. Nothing in our code sets it (the plan's grep of src/ found it only in comments), and the pattern (present on a page that renders a form, absent on a plain text route) matches ASP.NET Core's antiforgery, which adds it when it writes a token. I have not confirmed that source, so treat it as likely rather than proven. Either way it agrees with frame-ancestors 'self', and frame-ancestors takes precedence in browsers that understand both.

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

E2E tests passed

362 passed, 0 failed, 4 skipped in 14 min 26 s

Commit 5759bcb against https://check-performance-data-pr-642.test.teacherservices.cloud (run)

The directive comment said the app has never sent X-Frame-Options. Our
code never set it, but ASP.NET Core's antiforgery adds SAMEORIGIN to
every page that renders a token, which the review-app proof shows on
the start page. The comment now says so, so a reviewer who curls the
app does not read it as wrong.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ajs-uk-dev
ajs-uk-dev merged commit ac8442a into main Oct 19, 2026
9 checks passed

This branch was successfully deployed

1 active deployment
review — 5759bcb1 Deployed Oct 19, 2026 by ajs-uk-dev via Delete Review App 642 #344
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add frame-ancestors to the content security policy

2 participants