Skip to content

Fix CNCFProjectCard href allowlist bypass in renderProjectCards() - #250

Open
mrbobbytables wants to merge 1 commit into
mainfrom
fix-project-card-href-validation
Open

mrbobbytables wants to merge 1 commit into
mainfrom
fix-project-card-href-validation

Conversation

@mrbobbytables

Copy link
Copy Markdown
Member

Summary

Fixes #247.

renderProjectCards() in scripts/import-architectures.mjs picked the URL for every published <CNCFProjectCard> with a bare substring test:

links.find((link) => link.includes('cncf.io/projects/'))

String.prototype.includes matches anywhere in a URL — query string, fragment, path, or userinfo — so any host can satisfy it. Content comes from the upstream cncf/architecture repo, imported unattended daily and published without link review, so a crafted upstream Markdown link (e.g. https://evil.example/r?u=cncf.io/projects/kubernetes/) could make a CNCF-branded card link to an attacker-controlled origin.

Fix

  • Added scripts/lib/project-card-links.mjs exporting isCncfProjectHref(), which uses real URL parsing to require: https: protocol, no userinfo, a hostname of cncf.io or a *.cncf.io subdomain, and a /projects path.
  • Wired the predicate into renderProjectCards() in place of the substring check, with the same fallback to the constructed www.cncf.io URL when no upstream link qualifies.
  • Added tests/project-card-links.test.mjs covering: the reported bypass URL, a cncf.io.evil.example lookalike host, a userinfo bypass, an http:// downgrade, a non-/projects cncf.io path, a non-URL string, and the legitimate https://www.cncf.io/projects/kubernetes/.

All 50 cards currently generated in docs/architectures/*.md already use https://www.cncf.io/projects/<slug>/, so this produces no output change for today's upstream data — it only closes the bypass.

Scope

Deliberately scoped to renderProjectCards() only, per the issue's scope note. The separate logo= hot-linking issue and PR #195 (mirrorProjectAssets() / sanitizeArchitectureAssets()) are untouched.

Testing

  • npm run test:unit — all 63 tests pass (8 new)
  • npx prettier --check on changed files — passes

— hive: backend=copilot model=claude-sonnet-5

🐝 Hive Agent: contributor | SHA: 47705c9

renderProjectCards() in scripts/import-architectures.mjs picked the URL
for every published <CNCFProjectCard> with a bare substring test
(link.includes('cncf.io/projects/')). Since String.prototype.includes
matches anywhere in a URL, an upstream architecture Markdown file could
embed a link such as
https://evil.example/r?u=cncf.io/projects/kubernetes/ and have it
selected as the card href, pointing a CNCF-branded card at an
attacker-controlled origin.

Add scripts/lib/project-card-links.mjs exporting isCncfProjectHref(),
which uses real URL parsing to require https, no userinfo, a host of
cncf.io or a cncf.io subdomain, and a /projects path. Wire it into
renderProjectCards() in place of the substring check, and add unit
tests covering the reported bypass, a lookalike host, a userinfo
bypass, an http downgrade, and the legitimate cncf.io project URL.

Fixes #247

Signed-off-by: mrbobbytables <mrbobbytables@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant