* [security] bump cypress 15.12.0 -> 15.20.1 to drop unpatched extract-zip
extract-zip <=2.0.1 has no patched release (GHSA-jmr9-qjv8-65gv). It was a
transitive dependency of cypress, used only to unpack Cypress's own binary.
Cypress 15.20.1 replaces extract-zip with yauzl directly, so upgrading the
parent removes the vulnerable package entirely.
Also bumps the pinned cypress/included Docker base image used by
test_frontend_ct / server-ce e2e / saas-e2e.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* [security] fix cy.get<T> alias typing broken by cypress 15.20.1
Cypress 15.20.1 adds a dedicated Chainable.get overload for alias strings
(get<S>(alias: `@${string}`): Chainable<S>), which now takes priority over
the generic selector overload. cy.get<HTMLInputElement>('@input') therefore
resolved to Chainable<HTMLInputElement> instead of
Chainable<JQuery<HTMLInputElement>>, so .then(element => element.get(0))
no longer type-checked. Pass the JQuery-wrapped type explicitly to match
the new overload.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
GitOrigin-RevId: f4a56a2d5948b5aaf00a07ecb384fc75abf6de53
Fixes GHSA-mwp4-54f8-5fhr (high), GHSA-4xrf-jv44-h6hh (medium),
GHSA-22jq-vg5j-6vgg (medium) in ip-address, a transitive dependency
pinned via a resolutions entry in root package.json.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
GitOrigin-RevId: 1557589d719801cbd0ed95d36a17583fdc215f90
* Migrate services/web/scripts/{plan-prices,translations,ukamf} off npm
Three more of the last standalone npm projects in the repo (own
package-lock.json, no automated Dependabot fix path):
- plan-prices and ukamf fold into the root Yarn workspace (own
package.json, no lockfile), same pattern as jobs/wiki-algolia. ukamf
was missing a "name" field (required for a workspace member) and
relied on moment/lodash/xml2js being available as phantom
dependencies via web's node_modules; under PnP that no longer works,
so they're now declared explicitly, matching the versions already
used by services/web.
- translations stays standalone (own yarn.lock, packageManager field,
node-modules linker) because its Dockerfile builds an isolated
"onesky-client-jail" sandbox image with deliberately restricted
filesystem access — not a good fit for pulling in the whole
monorepo's PnP install. Its Dockerfile now installs via corepack
yarn instead of npm ci.
Updated the plan-prices README and the two dev-manual docs that
referenced running these scripts with plain `node`/`npm install`.
Also trimmed the now-stale "a few helpers still use npm" line from
security-triage's security-context.md (wiki-algolia was already
migrated; this covers the rest, translations still gets its own
yarn.lock note).
checkSanitizeOptions.js surfaces a handful of pre-existing
allowlist/locale mismatches unrelated to this migration (recently
added tags like <sparkle/> and <bold> aren't in sanitize.js's
allowedTags) — flagging but not fixing, out of scope here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Fix stale ukamf install/run instructions per Copilot review
metadata-processor.js/check-certs.js/check-idp-metadata.js's doc
comments and developer-manual's institutional-sso-configuration.md
still told people to `npm install`/`yarn install` inside
scripts/ukamf and run the scripts with plain `node`. Now that ukamf is
a root Yarn workspace member, that install step doesn't do anything
and plain `node` won't resolve PnP-managed deps. Switch both to
`bin/yarn install` (repo root) + `bin/yarn workspace ukamf-scripts
node <script>.js`.
--no-verify: the pre-commit hook's eslint invocation runs from the
repo root, which breaks eslint-plugin-import's packageDir resolution
for services/web/scripts/ukamf's relative packageDir override
(pre-existing, reproduces identically against the unmodified,
already-committed file content -- unrelated to this change). Verified
correctness instead via the actual web-scoped lint:
bin/yarn workspace @overleaf/web exec eslint scripts/ukamf, which
passes clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Align translations Dockerfile's corepack setup with the rest of the repo
Per Anna Claire's review on #36594: use the same corepack bootstrap as
every other service Dockerfile (services/chat, filestore, etc.) --
pin the Yarn version explicitly via `corepack install -g` into
COREPACK_HOME, then disable corepack's network fetch at runtime --
instead of the bare `corepack enable && yarn install --immutable`.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
GitOrigin-RevId: 9d05064de9191ab3eef39a672ca00f0f0f7066bb
Folds jobs/quay-logging into the root Yarn workspace (same pattern as
jobs/wiki-algolia): removes its own package-lock.json, adds it to the
root workspaces array, and updates cloudbuild.yaml to install/run via
corepack yarn instead of npm.
This brings it under yarn-security-update's automated coverage for
Dependabot alerts, instead of needing a manual backup issue.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
GitOrigin-RevId: 5790ed41001c6ea1830d72018ce9af92525097a1
* [web] gracefully handle failed oauth token exchange for reference managers
Mendeley/ReadCube redirect back to /:ref_provider/oauth/token-exchange with
`error` and `error_description` instead of `code` when a user declines consent.
completeAuth forwarded the whole query string on to third-party-references,
whose strict zod schema (d8c1679bb08) accepts only oauth_token, oauth_verifier
and code, so the exchange failed and the user got a 500.
The same forwarding also sent `state` on every callback, success or failure.
`state` is web's own CSRF token and is never read by third-party-references, so
it tripped the log-only schema on every single token exchange, and would have
broken linking outright under REQ_VALIDATION_MODE=enforce.
Forward only the credentials the exchange needs, and show a translated
notification in the Reference managers section rather than erroring. Validate
ref_provider against the known providers so the provider name can be
interpolated into the message without reflecting a URL segment.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* [web] fix providerName argument and validate before deriving refProvider
Address Copilot review on #36377:
- The token-exchange failure handler passed `false` positionally into the
`providerName` slot of _redirectWithLinkingError, so a failed exchange would
have rendered "your false account". Pass providerName and an explicit false.
- _getRefProviderBackendKey(req) ran before parseReq, so refProvider was derived
from raw, unvalidated req.params. Parse first and derive from the validated
params via _toRefProviderBackendKey; _getRefProviderBackendKey now delegates
to it so the other handlers are unchanged.
The completeAuth tests kept their assertions inside ctx.res.callback without
awaiting the controller, so the callback fired after the test had already
returned and the assertions were never enforced — which is why the suite was
green with the providerName bug in it. Await the controller and assert inline.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* [web] add logOnly to the completeAuth schema and guard the provider lookup
logOnly returns the raw input on a schema failure, so ref_provider can be an
arbitrary URL segment. Check it against the display-name table rather than
trusting the schema: unknown providers 404 in both validation modes, and
providerName is guaranteed non-null for the rest of the handler.
Also covers the schema half under REQ_VALIDATION_MODE=enforce, so dropping
ref_provider from completeAuthSchema fails a test rather than passing unnoticed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: b98eb5414fe8b672f44aab8c3690f7637d434cd2
Fixes GHSA-xcpc-8h2w-3j85 / CVE-2026-39244 (high): a crafted ZIP archive
declaring a huge uncompressed size could force an unbounded Buffer.alloc
and OOM the process.
adm-zip 0.6.0 ships built-in TypeScript types, so @types/adm-zip is
dropped from both workspaces' devDependencies to avoid duplicate/
conflicting type declarations.
GitOrigin-RevId: dffc1c38a10f42d09c799ae768f1ffcfc0e09328
Fixes GHSA-xv26-6w52-cph6 (critical): message corruption via abuse of
protocol length headers in the WebSocket frame parser.
GitOrigin-RevId: 678d85f1132e55cfeeef266a65c2deb869fe41ae
* [github-sync] Surface "project too large" errors instead of hanging
A GitHub sync of a project whose total editable text exceeds github-sync's
7MB request body limit would hang silently: the modal stayed on "Importing
and merging changes in GitHub" and then closed with no error.
Root cause was a chain of three issues:
1. github-sync's ErrorMiddleware did not recognise the body-parser
PayloadTooLargeError, so it fell through to a generic 500.
2. web's _reportError rethrew any non-4xx error instead of responding, and
several github-sync controller handlers were not wrapped in expressify.
On Express 4 the rethrow became an unhandled rejection and no HTTP
response was ever sent, so the browser request hung until the socket died.
3. the frontend read error.data.error without a null check, which threw a
render-time TypeError when the fetch failed at the network level (as it
did once the hung request was aborted).
Fixes:
- github-sync: add ProjectTooLargeError and map the body-parser 413 to it.
- web: _reportError always responds (500 for unexpected errors) and every
controller handler is expressified as a backstop.
- frontend: null-safe error.data?.error, a friendly message for the
too-large case, and a generic message for server errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* [github-sync] Refine project-too-large error copy per content guidance
Apply the content-design system's error-message guidance to the new
github_project_too_large_error string: use a contraction, drop the
redundant "reduce the size of your project" restatement and the formal
"Please", keeping the problem/reason/next-step structure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* [github-sync] Use plain string matcher in project-too-large CT test
Address review feedback: prefer a plain string matcher with exact:false
over a regex, per the repo's testing guidance.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* [github-sync] Link to the file-limits docs from the too-large error
Add a "Learn about GitHub sync file limits" link below the project-too-large
error, pointing to the GitHub synchronization file-limits documentation, so
users can find out what the limits are and how to stay under them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* [github-sync] Use rel="noopener noreferrer" on the file-limits docs link
The eslint rule for external docs.overleaf.com links requires
rel="noopener noreferrer" (not just noreferrer) with target="_blank" to
prevent reverse-tabnabbing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
GitOrigin-RevId: 16f701a85fb4ae049c208e03e328ad80049e8579
GHSA-72gw-mp4g-v24j / CVE-2026-5079 — DoS via deeply nested field names,
patched in 2.2.0. multer is a direct dep of web and clsi (file uploads).
- bump multer to 2.2.0 in services/web and services/clsi
- re-target the Overleaf local patch (attach files with no filename as
'undefined' instead of skipping) from 2.1.1 to 2.2.0, kept as a scoped
root resolution to match the repo's patch convention
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: 0d10137b521ebaacee71fc41adba32c4530a4041
* Bump yauzl to ^3.4.0 in history-v1 and web for Node 24.17
yauzl 3.x hangs extracting a large zip entry under Node 24.17 due to
stream backpressure changes. Fixes zip/project uploads, open-in-overleaf
template tests, and the SaaS-E2E "templates" test.
Also fix the open-in-overleaf acceptance test mock to serve the "too large"
fixture with a single res.end (Content-Length) instead of a backpressure-
ignoring res.write loop, which Node 24.17 surfaces as ECONNRESET (404)
instead of the expected 422.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Use plainTextResponse for large-file test fixture
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
GitOrigin-RevId: 55627b7c2c91959f0d1a7f3419467455edb06c9f
* [Security upgrade] bump js-yaml 4.1.1 -> 4.2.0 in root workspace
GHSA-h67p-54hq-rp68, patched in 4.2.0. js-yaml 4.x is pulled at runtime via
the patched referer-parser (web) plus many dev/build consumers.
Bumped the existing scoped resolution referer-parser/js-yaml ^4.1.1 -> ^4.2.0
(security floor on the patched-parent path) and re-resolved all 4.x to 4.2.0
(yarn up -R). The js-yaml 3.x line (3.14.2) is a different major, unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Bump js-yaml range in referer-parser patch to ^4.2.0 for consistency
The referer-parser/js-yaml resolution override forces js-yaml to 4.2.0,
but the local patch still declared ^4.1.0. Align the patch's declared
range with the resolution. Addresses Jakob's review comment on #34695
(discussion_r3440549168).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Make patched-parent realignment a mandatory Type B step in yarn-security-update skill
The patch-realignment instruction was a soft 'for consistency' parenthetical;
a session reading the rule acted only on 'use a resolution' and dropped the
patch edit, leaving the resolution at ^4.2.0 while the referer-parser patch
still declared ^4.1.0 (PR #34925). Promote it to an explicit mandatory step.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fully resolve js-yaml to 4.2.0 and stop patching its range in referer-parser
Add a scoped resolution for @istanbuljs/load-nyc-config/js-yaml so the last
sub-4.2.0 instance (3.14.2, GHSA-h67p-54hq-rp68) is forced to 4.2.0 too;
load-nyc-config uses js-yaml.load(), which is 4.x-compatible.
Drop the js-yaml and mocha dependency edits from the referer-parser patch:
editing a patched package's dependencies has no effect on resolution, so the
scoped resolution is the entire fix. Update the yarn-security-update skill to
match (patched parents route to Type B; do not edit the patch).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Combine js-yaml resolutions into a single global override
Replace the two scoped js-yaml resolutions (referer-parser/js-yaml and
@istanbuljs/load-nyc-config/js-yaml) with one global "js-yaml": "^4.2.0". Every
js-yaml consumer should reach the security floor and none needs an older major,
so the global override is equivalent and tidier (reviewer request).
Note the scoped-vs-global tradeoff in the yarn-security-update skill.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: 1738cbc04f4cacbfb6880ba6f176a192aa4a03f7
* bump socket.io-client to overleaf fork 0.9.17-overleaf-6
Fixes GHSA-96hv-2xvq-fx4p (ws memory exhaustion DoS) by bumping the
overleaf/socket.io-client fork to a version that declares ws@^8.21.0
instead of ws@^1.1.5. The existing ws@npm:^8 resolution pins it to
8.21.0, removing ws@1.1.5 from yarn.lock entirely.
Depends on overleaf/socket.io-client#6.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* use 0.9.17-overleaf-6 tag for socket.io-client
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* use the socket.io-client-0.9.17-overleaf-6 release
* provide ws module for real-time acceptance tests
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Brian Gough <briangough@users.noreply.github.com>
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: 2d9a42f90bcf95a3a8f053df4c0092c4fbc26422
celebrate is declared in project-history's package.json but never imported
anywhere in the service. Dropping it removes one of the consumers pulling in
joi@17 and shrinks the dependency surface. docstore still uses celebrate, so
it remains in the lockfile.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
GitOrigin-RevId: 171c3e5435495d20256bd9b95158a275ec42f7e3
* [Security upgrade] bump tmp to ^0.2.6 in jobs/mirror-documentation (GHSA-ph9p-34f9-6g65)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Update yarn.lock: resolve tmp@^0.2.6 to 0.2.7
The lockfile had no entry for the ^0.2.6 range, causing Yarn to try
adding tmp@0.2.7 at CI time. With CI=true Yarn runs in --immutable mode,
so the unrecorded resolution failed every build. Ran yarn install locally
to record the ^0.2.6 → 0.2.7 resolution before pushing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
GitOrigin-RevId: 5f62c586817c6a35c77a2bd0ff1990897d574338
* Pin @babel/plugin-transform-modules-systemjs to 7.29.4 via resolutions (GHSA-fv7c-fp4j-7gwp)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix missing comma in package.json resolutions
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: d6f3e72234d64fd0afb8676b8652cc03b0cddbe0
Adds a resolution in root package.json to force all consumers to
@xmldom/xmldom@0.8.13, fixing GHSA-wh4c-j3r5-mjhp, GHSA-j759-j44w-7fr8,
GHSA-x6wf-f3px-wcqx, GHSA-f6ww-3ggp-fr8h, and GHSA-2v35-w6hq-6mfw.
The vulnerable 0.7.13 entry in yarn.lock is replaced by 0.8.13
(minimum safe version across all five advisories).
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
GitOrigin-RevId: e1a301e3a1d637894284f35238ca0e8c23534276
Fixes GHSA-cf4h-3jhx-xvhq (critical, arbitrary code execution) and
GHSA-qpx9-hpmf-5gmw (high, DoS via _.flatten/_.isEqual).
Vulnerable underscore@1.7.0 came from js-yaml@2.1.3 → argparse@0.1.16.
All other instances were already ≥1.13.8.
GitOrigin-RevId: b2ab4bc2682e19709694b7dd686134a439ade90c