fix(security): address upload path validation vulnerabilities from PR #14 review - #28
Conversation
…14 review (#24) - Extract validateUploadPath and validateTabId into src/upload-validator.ts so all callers share a single hardened implementation. - Eliminate TOCTOU race in validateUploadPath: remove existsSync pre-check; realpathSync now throws ENOENT atomically with the path resolution, closing the symlink-swap window between existence check and real-path resolution. - Expand sensitive-path denylist: add ~/.netrc, ~/.npmrc, ~/.git-credentials, ~/.pypirc, /proc/self/environ, shell history files (~/.bash_history, ~/.zsh_history, ~/.sh_history), ~/.env, /etc/passwd, and .env files anywhere on the filesystem. - Reject overly-broad COMET_UPLOAD_ROOT values: "/" and homedir() are now rejected both before and after symlink resolution. - Tighten validateTabId to strict UUID v4 regex: replaces the loose /^[A-Fa-f0-9-]{16,64}$/ pattern that allowed hyphens in any position. - Add path validation in cdp-client.ts uploadFile() and uploadFiles(): validateUploadPath is now called at the CDP layer (defense-in-depth) so any future caller is protected regardless of whether it goes through the MCP tool handler in index.ts. - Create src/http-bridge.ts (source for dist/http-bridge.js) with: * crypto.timingSafeEqual for token comparison (replaces timing-unsafe ===) * Configurable CORS via COMET_BRIDGE_CORS_ORIGIN env var; wildcard "*" is never emitted (unsafe with bearer-token auth) * validateTabId() called in handleTabs() switch/close actions * comet_upload handler with validateUploadPath() enforcement
Security Review — PR #28 (commit
|
| Check | Result |
|---|---|
TypeScript build (tsc) |
PASS — no errors |
| New env vars in docs | ADVISORY — COMET_BRIDGE_CORS_ORIGIN not in README (see below) |
| Secrets detection | PASS — no secrets in diff |
| Package.json changes | N/A — no dependency changes |
Positive Findings
All 6 original PR #14 review vulnerabilities are correctly addressed:
- TOCTOU eliminated:
existsSyncremoved fromvalidateUploadPath;realpathSyncwraps correctly with ENOENT catch. - Denylist expanded: Added
~/.netrc,~/.npmrc,~/.git-credentials,~/.pypirc,/proc/self/environ, shell histories,.envfiles anywhere on filesystem,/etc/passwd. - Root rejection:
COMET_UPLOAD_ROOT="/"andCOMET_UPLOAD_ROOT=homedir()rejected both before and after symlink resolution. Robust. - UUID v4 regex:
validateTabIdcorrectly uses/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/. Chrome CDP target IDs are UUID v4 — this is the correct format. - CDP-layer validation:
uploadFile()anduploadFiles()incdp-client.tsboth callvalidateUploadPathat entry. Double-validation when called via index.ts is harmless (second call on already-resolved path is a no-op). - HTTP bridge security:
timingSafeEqualwith equal-length buffer guard, no wildcard CORS,validateTabIdin both switch and close actions,comet_uploadhandler with path validation.
Findings
Finding 1 — POSSIBLE / MEDIUM
File: src/upload-validator.ts line ~148
Pattern: incomplete-denylist-coverage
The denylist adds /proc/self/environ (correct), but does not block the broader /proc/self/ prefix. An attacker could target /proc/self/maps (reveals memory layout), /proc/self/fd/3 (open file descriptors that may reference sensitive files), or /proc/1/environ (init process environment). These are regular files readable under the PR threat model.
Recommendation: Replace the single /proc/self/environ entry with /proc as a prefix (blocks all of /proc subtree). This is a narrow follow-up fix — the current PR already addresses the highest-risk entry.
Confidence: POSSIBLE (threat requires a specific attack scenario; the most obvious vector /proc/self/environ is already blocked)
Severity: MEDIUM
Finding 2 — POSSIBLE / LOW
File: README.md
Pattern: missing-env-var-documentation
COMET_BRIDGE_CORS_ORIGIN is introduced in src/http-bridge.ts with clear inline documentation but the top-level README has no HTTP bridge section at all (COMET_BRIDGE_TOKEN, COMET_BRIDGE_PORT, COMET_BRIDGE_HOST are also undocumented there). The existing HTTP bridge section in dist/http-bridge.js header covers this via JSDoc comments, so the gap is informational rather than a functional issue.
Recommendation: Add a brief HTTP Bridge section to README. Non-blocking — can be a follow-up issue.
Confidence: POSSIBLE
Severity: LOW
Verdict
APPROVED — All 6 original blocking vulnerabilities are correctly fixed. Both findings above are advisory (POSSIBLE confidence, MEDIUM/LOW severity) and do not constitute blocking issues for this security-fix PR. The /proc coverage gap is a follow-up improvement, not a regression.
RapierCraft
left a comment
There was a problem hiding this comment.
APPROVED: commit 91342d9 after security-domain review (1 agent). 2 findings created as issues — both POSSIBLE confidence, non-blocking. PR correctly addresses all 6 original vulnerabilities from PR #14 review. Safe to merge.
Review findings:
- Issue #29: expand /proc denylist to block entire subtree (MEDIUM, follow-up)
- README documentation gap for COMET_BRIDGE_CORS_ORIGIN (LOW, informational)
PR Review Summary: #28 — fix(security): address upload path validation vulnerabilities from PR #14 reviewReview IntegrityReviewed commit: Verdict: APPROVEDContext-Aware ReviewDomains: Security, Path Validation, Token Auth, CORS Integration Checks (Phase 2.5)Code registration: PASS — all new modules compile and import correctly Risk Matrix
Findings
Automated Checks
RecommendationAll 6 original PR #14 vulnerabilities are correctly fixed. The two review findings are low-priority follow-ups that do not block this security fix PR. Merged to Security review complete. 1 agent + integration checks. 2 findings triaged. PR merged. |
Summary
Addresses all 6 security vulnerabilities identified in the PR #14 review. Validators are extracted into a shared module, the HTTP bridge is brought under source control with fixes applied.
Changes
src/upload-validator.ts(new): SharedvalidateUploadPath()andvalidateTabId()— single source of truth for all callers.existsSyncpre-check;realpathSyncnow resolves atomically~/.netrc,~/.npmrc,~/.git-credentials,~/.pypirc,/proc/self/environ, shell histories,.envfiles anywhere on filesystem,/etc/passwdCOMET_UPLOAD_ROOT="/"andCOMET_UPLOAD_ROOT=homedir()(before and after symlink resolution)validateTabIdtightened to strict UUID v4 regexsrc/index.ts(modified): Imports validators from shared module; removes inline definitions and unused importssrc/cdp-client.ts(modified): CallsvalidateUploadPath()at entry ofuploadFile()anduploadFiles()— defense-in-depth at the CDP layersrc/http-bridge.ts(new — source fordist/http-bridge.js):crypto.timingSafeEqualreplaces timing-unsafe===for token comparison*; configurable viaCOMET_BRIDGE_CORS_ORIGINenv varvalidateTabId()called inhandleTabs()switch/close actionscomet_uploadhandler added withvalidateUploadPath()enforcementTesting
~/.netrc— expect rejection [type:manual]COMET_UPLOAD_ROOT="/"— expect "overly broad" error [type:manual]GET /toolsincludescomet_upload[type:api]COMET_BRIDGE_CORS_ORIGINunset [type:api]Closes #24
Implementation branch:
fix/upload-path-security-24Base:
main