mirror of
https://github.com/millionco/react-doctor.git
synced 2026-09-14 20:00:24 +08:00
0a231000bb
* fix(scripts): escape leaderboard entries before writing them into README `update-leaderboard.ts` interpolated `entry.name` and `entry.githubUrl` directly into a markdown table that the workflow later commits to the canonical README. A compromise of the upstream benchmarks repo could land arbitrary markdown (or HTML that GitHub's renderer accepts, like `<img>`) into the README and from there onto npm via the published `react-doctor` package's README field. Escape repo names against the markdown table grammar (backslash, pipe, brackets, backtick, angle brackets, newlines), reject entries whose `githubUrl` doesn't parse as an `https://github.com/...` URL, and `encodeURI` the URL before substituting so a stray space or paren can't terminate the markdown link target. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com> * fix(website): validate leaderboard github URLs to prevent XSS via href The hosted leaderboard rendered `<a href={entry.githubUrl}>` with no protocol check. `entry.githubUrl` is read from `react-doctor-benchmarks` (a separate repo), so a compromise of that repo could land a `javascript:` href on react.doctor. React 18+ no longer blocks `javascript:` URLs in href, so this was a live XSS path even without a same-origin cookie story. Parse each URL through the WHATWG URL constructor and only keep entries whose protocol is `https:` and whose host is exactly `github.com`. Filter happens at fetch time so every downstream render uses the sanitized list. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com> * fix(security): zip-slip + git-flag-injection defenses for the Effect-based services Re-applies the two source-side security fixes from #428 onto the current Effect v4 services (the original commits were authored against the pre-refactor sync helpers in get-staged-files.ts / get-diff-files.ts that no longer exist). ## 1. Zip-Slip: staged path traversal `StagedFiles.materialize` was resolving each staged path with `path.join(tempDirectory, relativePath)`, which happily expands `..` segments outside the temp dir. A deliberately crafted index entry (via `git update-index --add`, a malicious pack, or a symlinked working tree) could write attacker-controlled files anywhere the running user can write. Added `isPathInsideDirectory(child, parent)` helper, resolved `tempDirectory` up front, and the per-file loop now resolves the candidate against the resolved temp dir and `continue`s when the result falls outside. Same shape as the standard Zip-Slip defense. ## 2. CVE-2018-17456: git-flag injection via --diff <base> `Git.diffSelection` was forwarding `explicitBaseBranch` to `git rev-parse --verify <branch>` and `git merge-base <branch> HEAD` unchanged. A value starting with `-` (e.g. `--upload-pack=evil`) gets parsed by git as an option instead of a refname — the CVE-2018-17456 shape. Added `isSafeGitRevision(candidate)` at the top of the Git service and a check at the start of `diffSelection`. The validation runs BEFORE any subprocess spawn, so a malicious ref never reaches `ChildProcess`. Rejects: empty, leading `-`, leading/trailing `.`, embedded `..`, `@{` reflog suffix, or any character outside `[A-Za-z0-9_./-]`. In the canonical CI path the GitHub composite action already guards with `case "$DIFF_BASE" in -* )` before the CLI is invoked, so today's exposure is limited to local CLI runs where the user is attacking themselves. Hardening the library boundary anyway so other callers don't have to re-implement the check. ## Regression tests - `Git.diffSelection — git-flag injection` (6 cases): leading dash, `..` rev-range, `@{` reflog, shell metacharacters, leading dot, empty. Uses `Git.layerNode` because validation runs before any spawn, so the suite never reaches `git`. - `StagedFiles.layerNode — Zip-Slip defense` (1 case): a staged index containing `../escaped.ts` writes only the inside-the-temp file and never touches the parent dir. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>