security: secrets audit + hardened headers (enforced CSP), CodeQL, contact-endpoint hardening - #17
Merged
Conversation
Audit of this public repo confirmed no secrets/tokens are committed (current
tree or full history). Applied defense-in-depth hardening for the few abuse
vectors found:
- api/contact.js: strip control chars (incl. CR/LF) from input so it can't
smuggle structure into the email subject/headers; add a best-effort
per-instance rate limit (5/min/IP -> 429) to blunt floods that would burn
the Resend quota or spam the inbox.
- .github/workflows/promote-to-main.yml: pass `inputs.pr_title` and
`github.actor` through `env` instead of interpolating `${{ … }}` directly
into the run script (avoids the Actions shell script-injection antipattern).
- README: document the contact endpoint's anti-abuse posture and the durable
rate-limit upgrade path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138qS6baPZutQ7s2fMbfNv3
…canning Headers (vercel.json, applied to all routes): - Strict-Transport-Security (2y, includeSubDomains) — enforce HTTPS. - Permissions-Policy — deny camera/mic/geolocation/browsing-topics. - Content-Security-Policy-Report-Only — locks default-src to 'self' with explicit allowances for the self-hosted bundle/fonts, Vercel Analytics, and the Hugging Face media CDN. Shipped report-only so violations surface in the browser console / report endpoint on the live site before switching to an enforcing `Content-Security-Policy`; the HF CDN redirects to hosts that can't be enumerated from CI, so report-only is the safe first step. Verified locally: production build emits no inline scripts/styles, and serving dist/ with these exact headers returns all first-party assets (JS/CSS/fonts/ SVG/SPA route) 200 — the 'self' policy won't starve the page. Also adds a CodeQL code-scanning workflow (free for public repos) so results land under Security → Code scanning. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138qS6baPZutQ7s2fMbfNv3
Flipped Content-Security-Policy-Report-Only -> Content-Security-Policy after validating the policy with a headless Chromium against the production build: - Drove the full page (load + lazy-loaded showcase + contact POST) under the policy in ENFORCING mode and observed ZERO securitypolicyviolation events. - Confirmed the Hugging Face media chain resolves huggingface.co (302) -> cas-bridge.xethub.hf.co (206) -> us.aws.cdn.hf.co (206); both CDN hosts are covered by the existing `*.hf.co` allowance, so video posters/clips load. - Confirmed Vercel Analytics loads same-origin (/_vercel/...) under script-src 'self', and the contact form POST passes under connect-src 'self'. Report-only enforced nothing; this makes the policy active. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138qS6baPZutQ7s2fMbfNv3
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Security pass over this public repo. Confirmed no secrets/tokens are committed (current tree + all 284 history blobs scanned) and applied defense-in-depth hardening.
Changes
Response headers (
vercel.json, all routes)Strict-Transport-Security(2y, includeSubDomains)Permissions-Policy— deny camera/mic/geolocation/browsing-topicsContent-Security-Policy— enforcing.default-src 'self'with explicit allowances for the self-hosted bundle/fonts, Vercel Analytics (same-origin), and the Hugging Face media CDN (*.hf.co).Contact endpoint (
api/contact.js)429) to blunt floods that would burn the Resend quota or spam the inboxPromotion workflow (
.github/workflows/promote-to-main.yml)inputs.pr_title/github.actorthroughenvinstead of interpolating${{ … }}into the run script (avoids the Actions shell-injection antipattern)Code scanning (
.github/workflows/codeql.yml)Verification
securitypolicyviolationevents. Confirmed the HF media chainhuggingface.co (302) → cas-bridge.xethub.hf.co (206) → us.aws.cdn.hf.co (206)is covered by*.hf.co; Analytics loads same-origin underscript-src 'self'; contact POST passes underconnect-src 'self'.Repo settings enabled alongside this (free on public repos)
Secret scanning · Push protection · Dependabot security updates.
🤖 Generated with Claude Code