Conversation
…dings (#35) * fix(deps): resolve 12 Dependabot vulnerabilities via npm audit + postcss override Runs npm audit fix to resolve 11 of 12 flagged vulnerabilities in transitive devDependencies (eslint tooling, puppeteer chain, gray-matter): - @babel/core: arbitrary file read via sourceMappingURL (GHSA-4x5r-pxfx-6jf8) - ajv: ReDoS via $data option (GHSA-2g4f-4pwh-qvx6) - basic-ftp: path traversal + CRLF injection + 2x DoS (critical) (GHSA-5rq4-664w-9x2c, GHSA-6v7q-wjvx-w8wg, GHSA-rp42-5vxx-qpwr, GHSA-rpmf-866q-6p89) - brace-expansion: zero-step sequence DoS (GHSA-f886-m6hf-6m8v) - flatted: unbounded recursion DoS + prototype pollution (GHSA-25h7-pfq9-p65f, GHSA-rf6f-7fwh-wjgh) - ip-address: XSS in Address6 HTML-emitting methods (GHSA-v2v4-37r5-5v8g) - js-yaml: quadratic-complexity DoS via merge key handling (GHSA-h67p-54hq-rp68) - minimatch: 3x ReDoS via wildcard/extglob backtracking (GHSA-3ppc-4f35-3m26, GHSA-7r86-cg39-jmmj, GHSA-23c5-xmqv-rm74) - picomatch: method injection + ReDoS (GHSA-3v7f-55p6-f55p, GHSA-c2c7-rcm5-vvqj) - ws: uninitialized memory disclosure + memory exhaustion DoS (GHSA-58qx-3vcg-4xpx, GHSA-96hv-2xvq-fx4p) The 12th finding (postcss XSS via unescaped </style>, GHSA-qx2v-qp2m-jg93) could not be fixed by npm audit fix because Next.js bundles its own internal copy of postcss (node_modules/next/node_modules/postcss@8.4.31) that npm's suggested resolution would only fix by downgrading next to 9.3.3 - not viable. Instead: - Bump the direct postcss devDependency to ^8.5.10 (patched). - Add a package.json "overrides" entry pinning postcss to ^8.5.10 for every nested copy in the dependency tree, including the one bundled inside next, without downgrading next itself. Result: `npm audit` now reports 0 vulnerabilities (down from 12: 1 low, 6 moderate, 4 high, 1 critical). Verified `npm run build` and `npx tsc --noEmit` still succeed with no regressions. Co-authored-by: Thomas Bohn <bohn.tl@gmail.com> * fix(security): sanitize blog HTML, validate external podcast links, harden path resolution Addresses code-scanning findings in JS/TS application code: 1. XSS via dangerouslySetInnerHTML with unsanitized Markdown HTML (lib/blog.ts, app/blog/[slug]/page.tsx). remark-html does not sanitize its output, so raw HTML embedded in a blog Markdown file (local or Medium-synced) would be rendered as-is in the browser. Added sanitize-html with an explicit tag/attribute/scheme allowlist so <script>, event handlers, iframes, and non-http(s) URLs are stripped before content ever reaches dangerouslySetInnerHTML, while preserving normal formatting (headings, lists, links, code, images). 2. Unvalidated external URL used as link href (components/xanga/applets/NowListeningApplet.tsx). Podcast episode links are sourced from third-party RSS/iTunes responses (including an external RSS proxy), then rendered directly into an <a href>. A compromised feed or proxy could inject a javascript:/data: URL. Added toSafeHttpUrl() to allowlist only http/https schemes before a link is rendered, falling back to '#' otherwise. 3. Defense-in-depth path resolution guard (lib/blog.ts getBlogPost). Added resolvePostPath() to verify the resolved file path stays inside content/blog/ before reading it, guarding against path traversal if this function is ever reused outside the current build-time-only, generateStaticParams-derived call sites. Verified with npx tsc --noEmit, npm run build, and a rendered diff of generated blog HTML (headings/lists/links/code/strong all preserved) to confirm no visual or content regressions. Co-authored-by: Thomas Bohn <bohn.tl@gmail.com> * fix(ci): move github.sha/steps.outcome interpolation out of run: blocks CodeQL's Actions query suite flags any ${{ ... }} expression embedded directly inside a run: script block as a potential script-injection sink, since the substitution happens before the shell ever runs and can allow control-character/quote injection when the underlying context value is attacker-influenced. The three flagged spots in promote-sandbox-to-main.yml only interpolated github.sha (an immutable 40-char commit hash) and steps.lint.outcome (a fixed GitHub-controlled enum), so this workflow was not exploitable via untrusted PR/issue input. Fixed anyway for defense-in-depth and consistency with the env:-based pattern already used elsewhere in this same file (e.g. RUN_URL, VALIDATED_SHA in other steps): - 'Record lint outcome' step: steps.lint.outcome -> $LINT_OUTCOME env var - 'Close stale build-failure issue' step: github.sha -> $VALIDATED_SHA env var - 'Close stale promotion-failure issue' step: github.sha -> $VALIDATED_SHA env var No behavior change; only the mechanism for getting these values into the shell script changed. Co-authored-by: Thomas Bohn <bohn.tl@gmail.com> * chore(ci): pin third-party GitHub Actions to commit SHAs Supply-chain hardening flagged as a low-priority code-scanning finding: all actions/* steps referenced floating major-version tags (@v4, @V3), which can be repointed by the upstream maintainer (or an attacker who compromises their account/repo) to a different commit without any signal in this repo. Pinned every actions/* step in both workflows to the exact commit SHA currently published under that tag, with the resolved version kept as a trailing comment for readability/auditing: - actions/checkout -> 34e114876b0b11c390a56381ad16ebd13914f8d5 (v4.3.1) - actions/setup-node -> 49933ea5288caeca8642d1e84afbd3f7d6820020 (v4.4.0) - actions/configure-pages -> 1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d (v4.0.0) - actions/upload-pages-artifact -> 56afc609e74202658d3ffba0e8f6dda462b719fa (v3.0.1) - actions/deploy-pages -> d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e (v4.0.5) No behavior change - these SHAs are exactly what the @v4/@V3 tags currently resolve to. Co-authored-by: Thomas Bohn <bohn.tl@gmail.com> * fix(security): add CSP + Referrer-Policy meta tags, non-guessable JSONP callback name Addresses the remaining medium/low-priority code-scanning findings: 1. Missing security headers. This site is statically exported to GitHub Pages with no server, so it cannot send custom HTTP response headers (no _headers file support, no headers() config). Added the strongest mitigation available in that environment: a Content-Security-Policy and Referrer-Policy via <meta> tags in the root layout, scoped to the exact external origins the app calls (itunes.apple.com for the Now Listening JSONP request, api.allorigins.win + api.open-meteo.com for fetch() calls, images.credly.com for certification badge images, w.soundcloud.com for the Vibe Tunes iframe embed). script-src requires 'unsafe-inline' because Next's static export embeds a per-build RSC hydration payload as inline <script> content with no server available to issue nonces/hashes - documented inline. Note that X-Frame-Options, Strict-Transport-Security, and Permissions-Policy have no meta-tag equivalent and genuinely require a real HTTP header, which isn't achievable on GitHub Pages alone (would need a CDN/edge layer such as Cloudflare in front of the custom domain - out of scope for this repo). 2. Math.random() used to build a JSONP callback name in NowListeningApplet - switched to crypto.randomUUID() to avoid a predictable/collidable global name on window. Not security-critical (no auth/token use), fixed for defense-in-depth per the original audit's low-priority note. Validated with a headless-browser pass across every page (including the Xanga sidebar theme, which mounts every applet that calls an external API or embeds an iframe) listening for 'securitypolicyviolation' events and console errors: zero CSP violations, zero console errors. Confirmed via curl that the one widget showing no data (Hit Counter) is failing because countapi.xyz is unreachable at the network level (pre-existing, unrelated to this change), not because of the new CSP. Co-authored-by: Thomas Bohn <bohn.tl@gmail.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
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.
Sandbox validated and ready for production
This PR was opened automatically after
sandboxwas validated bythis workflow run.
npm run build): passed4a712c827c1487c0290ffbd47d2973b771415e6aCommits included in this promotion
Review checklist
This PR requires manual human review and must be merged by a person.
This automation will never merge it.