Skip to content

fix(security): harden glob matching, archive parsing, redaction and media handling - #6030

Open
waleedlatif1 wants to merge 1 commit into
stagingfrom
security-hardening
Open

fix(security): harden glob matching, archive parsing, redaction and media handling#6030
waleedlatif1 wants to merge 1 commit into
stagingfrom
security-hardening

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Security hardening split out of #6013 so it can be reviewed and merged on test evidence alone. No dependency changes — every fix stands on staging's existing re2js and tldts.

  • Glob matching (copilot VFS) — match with RE2 instead of micromatch's backtracking engine. The translation layer is hand-written, so it also rejects what RE2 would read differently: picomatch passes a user's \A/\z/\p{L} through verbatim and RE2 reads those as anchors and Unicode classes, which made \A**/** select every path and let \p{Any} consume the segment markers that encode the dot:false guarantee. Class ranges straddling the marker block are rejected for the same reason.
  • Archive parsing — the EOCD scan now covers the whole buffer. JSZip and SheetJS scan to offset 0 while only yauzl honours the spec's trailing window, so a single prepended byte plus 64 KiB of junk hid a 495x bomb. A resolvable-but-empty central directory is now unverifiable rather than fail-open, and scanning is bounded by a shared record budget. Stray EOCD byte sequences in non-ZIP documents stay a no-op so the OLE2 and plaintext fallbacks still run.
  • Redaction — fixes quadratic acronym-boundary backtracking (73s → 1ms at 400k chars) and catches plural, value-suffixed, and one-shot locator keys.
  • Other — YAML alias-expansion guard in the JSON/YAML chunker; fal.ai queue polling pinned to its origin with a capped body; ffmpeg drawtext values passed via file instead of the filtergraph; redirects resolved against the registrable domain with credential headers dropped across sites; file-preview error boundary retries instead of latching.

Type of Change

  • Bug fix

Testing

2,837 tests pass across 162 files; tsc, biome and check:api-validation clean.

Every security fix is pinned by a test proven to fail against the pre-fix code — the guards were verified by constructing working exploits, not by inspection. Two vacuous tests found during that process (one passed with the guard call deleted) were rewritten to discriminate.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…edia handling

Glob matching (copilot VFS):
- match globs with RE2 instead of micromatch's backtracking engine, and
  translate picomatch's output rather than trusting it: reject escape
  passthrough (\A, \z, \p{L}) that RE2 reads as anchors and Unicode
  classes, and class ranges straddling the private-use segment markers

Archive parsing:
- scan the whole buffer for EOCD records, matching JSZip and SheetJS
  rather than the spec's trailing window
- treat a resolvable-but-empty central directory as unverifiable
- bound central-directory scanning with a shared record budget
- keep stray EOCD byte sequences in non-ZIP documents a no-op so the
  OLE2 and plaintext fallbacks still run

Redaction:
- fix quadratic acronym-boundary backtracking (73s to 1ms at 400k chars)
- catch plural and value-suffixed secret keys, and one-shot locator URLs

Other:
- guard YAML alias expansion in the JSON/YAML chunker
- pin fal.ai queue polling to its origin and cap the response body
- escape ffmpeg drawtext values through a file instead of the filtergraph
- resolve redirects against the registrable domain and drop credential
  headers across sites
- let the file preview error boundary retry instead of latching
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 29, 2026 12:00am

Request Review

@cursor

cursor Bot commented Jul 29, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Touches SSRF-guarded fetches, redirect credential policy, copilot path matching, and archive parsing on untrusted input—areas where regressions could leak secrets or break provider integrations.

Overview
This PR tightens several security-sensitive paths: copilot VFS glob/grep, OOXML/YAML parsing, logging redaction, secure fetch redirects, video provider downloads, and file preview UX.

Copilot VFS glob no longer uses micromatch’s backtracking isMatch for caller-supplied patterns. Picomatch’s compiled regex is rewritten and executed via RE2 (compileLinearRegex), with length/wildcard caps, matcher caching, and fail-closed behavior when a pattern isn’t representable. Grep scopes that use */? share the same engine; GlobPatternError is surfaced from vfs glob/grep handlers like other validation errors. Large differential/semantics test suites lock equivalence to micromatch.

Zip/OOXML guards scan the full buffer for EOCD (not only a trailing window), handle prepended bytes, decoy EOCDs, count mismatches, ZIP64 declared sizes, and bounded walk budgets—rejecting forged expansion before JSZip runs. assertOoxmlArchiveWithinLimits is wired into doc-parser, copilot extractDocumentStyle, and existing xlsx paths. JsonYamlChunker loads YAML through assertYamlWithinLimits to block alias-expansion bombs.

Redaction reworks key normalization (fixes quadratic acronym splitting), expands sensitive-key rules (plural/value/locator keys, credential literals in strings, credentials container recursion), and aligns sanitizeEventData with user-file handling.

secureFetchWithPinnedIP redirects now use eTLD+1 same-site rules (tldts) and drop credential headers on cross-site hops (with carve-outs for idempotency/Atlassian tokens); stripAuthOnRedirect still strips Authorization on same-site hops.

Video tool API downloads provider URLs and polls Fal.ai queue endpoints through DNS-validated, IP-pinned fetches with response size caps; Fal queue URLs are origin-resolved/stripped (/response); Veo only attaches x-goog-api-key on genuine *.googleapis.com HTTPS hosts.

File viewer: PptxPreview is lazy-loaded; PreviewErrorBoundary offers in-place retry or “Reload page” for chunk-load failures. Loop while conditions serialize string outputs with JSON.stringify instead of manual quoting to block VM injection.

Documentation comment added for SheetJS CDN pin on OneDrive upload and xlsx parser.

Reviewed by Cursor Bugbot for commit 34ff739. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 34ff739. Configure here.

return (
<PreviewErrorBoundary key={file.id} label='PowerPoint'>
<PptxPreview file={file} workspaceId={workspaceId} />
</PreviewErrorBoundary>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PPTX boundary ignores content version

Medium Severity

The PowerPoint preview wraps PreviewErrorBoundary with key={file.id} only, while the PDF viewer keys its boundary with file.id and preview.dataUpdatedAt. After a preview crash, updating the same file’s binary without changing file.id leaves the boundary in its error state even though PptxPreview reloads internally, so users stay on the failure UI until they click Try again.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 34ff739. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Security hardening across glob matching, archive inspection, redaction, media tooling, and SSRF-sensitive fetches, with no dependency changes.

  • VFS globs compile via picomatch→RE2 rewrite with fail-closed caps instead of micromatch backtracking.
  • ZIP/OOXML guard scans full-buffer EOCD candidates, treats empty/unresolvable CDs as unverifiable, and bounds record walks.
  • Redaction normalizes key names (ReDoS-safe acronym split), expands secret/locator coverage, and display-filters user files.
  • Video/fal queue URLs stay on queue.fal.run with body caps; provider downloads use DNS-pinned fetch; Veo keys only on Google hosts.
  • Redirects drop credential headers cross-site (eTLD+1 + private PSL); ffmpeg drawtext uses textfile=; loop while-conditions use JSON.stringify; preview error boundary can retry/reload.

Confidence Score: 5/5

This PR appears safe to merge; the hardening paths are fail-closed or origin-pinned and are covered by discriminating tests.

Investigated glob RE2 translation, zip EOCD/CD fail-closed behavior, redaction user-file filtering, fal queue URL pinning, redirect credential stripping, ffmpeg drawtext isolation, loop condition serialization, and YAML alias guards; no concrete reachable defect remained after checking those contracts against callers and tests.

Important Files Changed

Filename Overview
apps/sim/lib/copilot/vfs/operations.ts Replaces micromatch.isMatch with RE2-backed compileGlobMatcher, segment markers for dot/newline semantics, and safety caps.
apps/sim/lib/file-parsers/zip-guard.ts Full-buffer EOCD scan, multi-candidate worst-case limits, unverifiable CD fail-closed, shared walk budget.
apps/sim/lib/core/security/redaction.ts Key normalization, broader secret/locator matching, credential containers, user-file display filtering, value-literal redaction.
apps/sim/lib/core/security/input-validation.server.ts Cross-site redirect credential stripping via tldts registrable domain; stripAuth still drops Authorization on same-site hops.
apps/sim/lib/media/falai.ts Origin-pinned queue URL resolution, /response strip, app-id polling path, capped JSON polls via secure fetch.
apps/sim/app/api/tools/video/route.ts Provider asset downloads and Fal polls go through SSRF-guarded clients; Veo API key gated on genuine Google hosts.
apps/sim/lib/media/ffmpeg.ts Overlay text written to temp textfile with double-escaped path; expansion disabled.
apps/sim/executor/orchestrators/loop.ts While-condition string interpolation uses JSON.stringify to prevent quote/newline breakout into the VM.
apps/sim/lib/chunkers/json-yaml-chunker.ts YAML load path runs assertYamlWithinLimits; complexity errors rethrow instead of text fallback.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-shared.tsx PreviewErrorBoundary retries in place or offers reload for chunk-load failures; PptxPreview lazy-loaded behind boundary.

Reviews (1): Last reviewed commit: "fix(security): harden glob matching, arc..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant