Repository navigation
Tags
Tags
Fix: SSRF hardening with an EE protection toggle and allowlist (#18600) * Fix: harden SSRF protection across data-source connectors and OAuth * Feature: honour SSRF runtime config in built-in plugin check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: exclude common package tests from tsc build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: honour SSRF runtime config in marketplace plugin check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: handle all:true in SSRF-safe DNS lookup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: honour SSRF runtime config in server helper, scope test connection Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: handle all:true in SSRF-safe DNS lookup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: SSRF instance settings and EE runtime publisher Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: SSRF settings endpoints for super admins Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: ungate SSRF settings routes from licence check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: SSRF toggle and allowlist on Security page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: one-time SSRF protection notice for super admins Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: link SSRF notice to /settings/security Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: SSRF runtime config context and release note Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: keep plugin tests out of the plugins build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: split Security page into sub-tabs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: keep plugin tests out of the plugins build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: add Security page heading Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: Security tab content spacing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test: run marketplace SSRF tests from plugins jest marketplace/ has no Jest runner, so the marketplace common SSRF suite never ran. The plugins Jest config now also roots at marketplace/plugins/common. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: block bracketed IPv6 literals in built-in SSRF check new URL() keeps the brackets on IPv6 hostnames and rewrites IPv4-mapped addresses to hex ([::ffff:7f00:1]), so the built-in copy's private-IP check missed [::1], [fd00::1], [fe80::1] and [::ffff:169.254.169.254], and Node skips the lookup hook for IP literals. The hostname is now unbracketed before the private-IP, allowlist and DNS steps (async and sync checks), and isPrivateIPv6 decodes the hex IPv4-mapped form, as the marketplace copy does. The bracket strip applies on every edition: it is a parsing bug, not a policy change, and CE users who opt in to SSRF protection are equally exposed. Also, under the EE runtime config a hostname with no DNS answer is now blocked (fail closed), matching the marketplace and server copies. IP literals skip DNS. Without the runtime config the empty answer still fails open, so CE/Cloud are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: check blocked schemes before the SSRF allowlist in plugin copies Both plugin copies returned on an allowlisted host before the scheme check, so gopher://jira.corp or ftp://10.0.4.12 passed once the host was allowlisted, while the server copy rejects them. An allowlist entry vouches for an address, not for a dangerous scheme. The built-in copy only has an allowlist under the EE runtime config, so the reorder is unconditional there. The marketplace copy also exempts loopback names by default on CE, so it checks the scheme early only when the runtime config is present, keeping CE/Cloud byte-identical. Same order in both sync checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test: cross-copy SSRF parity cases The same table now runs against all three SSRF check copies with the runtime key present: bracketed IPv6 loopback, ULA, AWS IMDSv6, IPv4-mapped loopback and metadata, and link-local literals are blocked; a hostname resolving into an allowlisted CIDR and an allowlisted IPv6 literal pass. Dropping the allowlist exemption from the DNS step now fails the server and marketplace suites. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: keep test-connection URL checks for every connector Scoping the test-connection SSRF check to a list of HTTP kinds dropped it for every kind not on the list (s3 endpoint, qdrant url, woocommerce host, every marketplace plugin) on all editions. The URL-style option check now runs for every kind again, and the host/port/protocol check runs for every kind except a deny-list of built-in database drivers, which is never applied when the request carries a plugin_id (that picks a marketplace plugin whatever kind says). The non-http protocol test now mocks DNS and asserts the call resolves, so it fails if the protocol coercion is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: describe runtime-config SSRF behaviour in server helper comments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: drop redundant close icon from SSRF notice Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: always enforce SSRF protection on Cloud in every check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: fail closed on empty DNS answers on Cloud Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: classify IPv6 addresses by their embedded IPv4 in every SSRF check IPv4-mapped (any spelling), SIIT, IPv4-compatible, NAT64, 6to4 and Teredo addresses are now judged by the IPv4 they carry, and ::, all of fe80::/10, fec0::/10 and ff00::/8 are blocked. Bracketed IPv6 literals are classified without brackets in the marketplace and server copies; under the runtime key and on Cloud a literal skips the DNS step, so public ones are allowed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: treat NAT64 local-use prefix as non-public in SSRF checks 64:ff9b:1::/48 can carry its IPv4 at any RFC 6052 offset, so decoding the last 32 bits let 127.0.0.1 hide behind a public-looking tail. The whole prefix is now blocked by every policy; 64:ff9b::/96 still decodes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: stop the SMTP connector reading local files or URLs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: keep SMTP test out of build and accept address objects Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: stop OAuth token exchange following redirects and pin the checked IP Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: resolve relative redirects before SSRF validation Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: note that public apps can reach allowlisted addresses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: classify hosts-file names against the SSRF allowlist resolve4/resolve6 never read /etc/hosts, so under the EE runtime config a hosts-file-only name was blocked even when its address was allowlisted. When DNS returns nothing, the three SSRF copies now fall back to dns.lookup and classify those addresses; CE and Cloud are unchanged. Also fixed the plugins and marketplace lint failures (prettier, and TypeScript tests now ignored like the JS ones). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: limit the test-connection database-kind skip to EE CE and Cloud check the host of built-in database kinds again, as before this branch; only EE with the SSRF runtime config skips them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: correct Cloud SSRF behaviour and SMTP address note Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: accept underscores inside SSRF allowlist hostnames Docker Compose service names such as my_service are now valid entries; a leading or trailing underscore is still rejected. Bumps frontend/ee for the matching client check and the banner-only-when-enabled fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Chore: log progress in the SSRF settings data migration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix: show SSRF allowlist as a scrollable table Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: disable SSRF protection in Cypress Marketplace runs * feat: rename SSRF protection to Private network access in the UI * feat: explain private network blocks and where to allow them Every block now names the host, says why (private address, resolves to one, or could not be resolved, keeping the resolver's own error), and on EE points to Settings → Security → Private network access. Same wording in all three copies of the check. * fix: show private network block reasons in HTTP connector errors REST API, GraphQL, OpenAPI, n8n, Confluence and ServiceNow wrapped every request failure as "Query could not be completed", hiding why a redirect or connect-time lookup was blocked. Blocks now keep their own message; other failures are unchanged. * feat: rename Private network access to Outbound requests * feat: leave SSRF protection off by default in dev mode The toggle is now seeded unset. Unset means off when the server runs with NODE_ENV=development (npm run start:dev) and on everywhere else; an explicit choice from the Security page always wins. * feat: keep SSRF protection as it was on existing setups The settings migration now tells a new installation (no workspace yet) from an existing setup. New installations get protection on by default; existing setups keep their current behaviour: off, or on if they had opted in with SSRF_PROTECTION_ENABLED=true. * feat: show the SSRF dashboard notice on new installations only * test: pin that a toggle turned off in the UI wins over SSRF_PROTECTION_ENABLED * test: cover every SSRF toggle default and upgrade case * fix: make the SSRF settings migration self-contained CI now rejects migrations that import project code. The migration uses raw SQL instead of entities and constants, and relies on the unique key (ON CONFLICT DO NOTHING) so a re-run never overwrites a stored value. * test: don't assume one localhost entry in the all:true lookup test * fix: restore edition-aware SSRF defaults in the plugins check The plugins and marketplace copies of the outbound request check are now identical, with a test that fails if they drift. CE is on by default again (loopback and metadata blocked, RFC1918 and localhost allowed), EE stays opt-in without the runtime config, Cloud is always on. Also bumps server/ee for the SAML picture check. * refactor: move SSRF settings into their own ssrf module The outbound requests settings API, its feature keys and setting keys move out of instance-settings into a new ssrf module, so instance-settings is back to its pre-SSRF state. AppModule only loads the ssrf module outside the migration app context: its runtime config publisher reads instance_settings on boot, which waited forever on the migration transaction's own lock and hung db:reset and fresh EE installs. The module also leaves the publisher out if it is ever imported there. Tokens cannot reach the new module. * chore: update submodule pointers * fix: give the SSRF settings data migration a real down() The migration authoring rules from the release line require every newer migration to undo up() or say why it cannot. down() now removes the three rows up() adds; the SSRF code reads missing rows as unset. * ci: disable SSRF protection in App Builder Cypress seeding * ci: skip the Cypress SSRF seeding step when the API is missing * adding submodule commit * test: bypass the SSRF check in the test-connection binding spec --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: gsmithun4 <gsmithun4@gmail.com>
Release v3.20.256 lts (#18945) * Bump version to 3.20.256-lts across all components * Auto-start trial for new users (#18828) * feat: skip auto trial and add trial_claimed_at to users * fix: tighten Cloud trial eligibility, skip auto-trial in tests - Bump server/ee and frontend/ee for the trial eligibility fixes - Jest: default DISABLE_AUTO_TRIAL=true so setup-super-admin doesn't call the license server - Shorten trial-related comments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * chore: update submodule pointers (#18935) * Feature: Land new users on the home page prompt after onboarding (#18961) * feat: skip auto trial and add trial_claimed_at to users * feat: send verified signups to the workspace home page On EE and cloud, a signup that skips the onboarding questions now lands on /<workspace>/home (the AI prompt) instead of the dashboard. CE and an explicit redirectTo are unchanged. Marks the sample onboard app endpoint as unused. * chore: update submodule pointers * chore: bump frontend/ee to merge release/v3.20.256-lts --------- Co-authored-by: Siddharthpl <siddharthpundir73@gmail.com> * Auto trial bug fixes (#18975) * chore: update frontend/ee for onboarding step 3 image fix * fix: report the license's own type after expiry Expired licenses are reported as basic, so the frontend couldn't tell an expired trial from an expired paid license. Add termsType to the license status and bump frontend/ee for the nav bar fix. * chore: drop lint-only reformatting from the release merge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: update frontend/ee pointer --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Update first-user onboarding spec for home-page landing (#18976) Onboarding no longer shows the free-trial page or the sample-app step (#18961, ee-frontend#870); after the workspace step the user lands on /my-workspace/home. Assert that landing and the home prompt header instead, and set retries to 0 since first-user setup is one-shot. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * bump version to 3.20.257-lts across all components --------- Co-authored-by: Siddharth Pundir <145639697+Siddharthpl@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Muhsin Shah C P <muhsinshah21@gmail.com> Co-authored-by: Siddharthpl <siddharthpundir73@gmail.com> Co-authored-by: Ajith KV <ajith.jaban@gmail.com>
Release v3.21.80-beta (#18561) * fix: guard organization invite acceptance against identity mismatch acceptOrganizationInvite() now verifies the logged-in caller's email matches the invite's target user before proceeding, mirroring the existing pattern in activateAccountWithToken. Covered by a unit test on the service-level guard and an e2e test on the full HTTP pipeline. * chore: bump frontend ee subm and sync skills * fix: tighten self-hosted workspace-signup password handling for existing accounts whatIfTheSignUpIsAtTheWorkspaceLevel() now only takes the instant-activation fast path when the existing account already has a password set. Accounts without one fall through to the existing invite-email flow instead. Covered by unit tests on the service-logic guard and e2e tests on the full HTTP pipeline. * fix: require a configured client ID before verifying Google OAuth tokens GoogleOAuthService.signIn now rejects sign-in when the SSO config has no clientId, instead of calling the underlying library with an undefined audience. Applies to both editions. Covered by unit and e2e tests. * fix: respect the configured signup setting on instance-wide SSO login OauthService.signIn no longer falls back to always allowing signup for instance-wide SSO logins; it now reads the same enableSignUp value used everywhere else in the flow. Covered by a unit test. E2e coverage for this specific path is blocked by a pre-existing, unrelated test-infrastructure issue, tracked separately. * fix: scope avatar file access to owner or same-org admin/builder * fix(deps): remediate high-severity Dependabot alerts in server (#5448) * fix(deps): remediate high-severity Dependabot alerts in root (#5447) * fix(deps): remediate high-severity Dependabot alerts in cli (#5440) * fix: patch adm-zip DoS vulnerability in plugins (GHSA-7q85-xj36-vmfc) adm-zip is pulled in transitively via ibm_db, which pins it below the patched 0.6.1 release. Add an override in plugins/package.json to force resolution to 0.6.1 regardless of ibm_db's declared range. * fix: scope User entity queries to safe fields (GH #17717) group-permissions' list-users-in-group endpoint returned unfiltered User rows (password hash, invitation/reset tokens) nested in the GroupUsers response; scoped the query to safe fields and added a strict response DTO with ClassSerializerInterceptor. Hardened several other unselected User queries in profile, app-permissions and group-permissions repositories that don't currently reach a response but were over-fetching sensitive columns unnecessarily. Updated the group-permissions e2e test to assert the new response shape. * chore: bump submodules * fix: scope app-environments lookups to the caller's workspace Verify that the version, app and environment ids sent to init, post-action, the environments list and the versions-by-environment endpoint belong to the caller's workspace before use, and reject a missing app_id on the versions endpoint instead of matching every app. Adds two-workspace e2e and unit specs and a module AGENTS.md. * chore: bump submodules * test: cover the CE app-environments workspace-scoping paths Run the two-workspace e2e spec against both editions, since the EE service overrides init, post-action and the list without calling the CE versions. * test: cover post-action with an app and environment from another workspace * fix(data-sources): stop test-connection from leaking secrets to attacker-chosen hosts for use-only users * test(data-sources): cover test-connection credential/secret binding regression * fix: scope folder_apps create/delete to the caller's workspace The folder_apps create/bulkCreate sinks resolved and moved a binding by app_id alone, with no organization_id in scope, and the ability factory granted admins CREATE/DELETE unconditionally. An admin — or a folder owner via the bulk app_ids path — could therefore bind another workspace's app into their own folder, disclosing the app's metadata and detaching it from the victim's folder. The ability guard now rejects any folder_apps mutation whose target folder or target app does not belong to the caller's workspace, for every role including admins. The create/bulkCreate sinks additionally assert app workspace membership as defense in depth. Advisories: GHSA-m46f-vj4w-2cpw, GHSA-mg7j-56p8-p2m2, GHSA-r2hw-m6w2-vmq7, GHSA-v675-3qmh-6rmf * chore: update server/ee submodule pointer * fix: authorize resource export Resource export now only operates on the caller's own workspace: a request whose organization_id differs from the session workspace is rejected, and ToolJet Database tables are always resolved against the session workspace rather than the id supplied in the body. Exporting an app additionally requires view access to that app (admin, super admin, all-apps view/edit, or the app in the user's viewable or editable set). App-create alone still grants import, and exports without an app keep their previous behaviour. * test: expect 403 when exporting an app with app-create only Export now requires view access on the app, so a developer whose only grant is app-create is denied. Admin export still succeeds. * fix: require a live session to list workspaces and disable unused TJDB join route The workspace list guard no longer treats the user as optional, so the session is validated while users can still switch away from archived workspaces. The TJDB join endpoint has no callers since join queries run server-side, so it is disabled. * fix: remove unused ToolJet DB join endpoint The HTTP join route had no callers; app join queries run in-process. Drop the route with its DTO, exception filters, feature key and the dead frontend service call. Add e2e coverage that ToolJet DB table routes stay scoped to the caller's workspace. * fix(data-sources): scope OAuth base-url constant resolution to session workspace, rejecting foreign organization_id (403) and out-of-workspace environment_id (404) before resolving secrets; adds regression tests * fix(data-sources): gate OAuth base-url endpoint to data-source configurers (admin/builder/create/configurable), returning 403 for viewers/end-users who were reaching decrypted secrets through it; adds ability unit tests * fix(data-queries): enforce app/workspace authorization on POST /:id/run so End Users can't run queries of unshared apps * fix(data-queries): bump server/ee for env-access guard fix (?mode=view bypass) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(data-queries): scope bulk query update to authorized version to prevent cross-app IDOR * fix(data-queries): confine anonymous public-app query runs to the released version (GHSA-grw5-2fvf-vwm4 / grh7-xf9j-r3qg) * fix(data-queries): confine anonymous public-app query runs to the released version * fix: enforce permission check on mutations for public apps * fix: require configure privilege to authorize shared-token OAuth2 data source * fix: scope data-sources dependent-queries by workspace to prevent cross-tenant leak * fix: restrict data source update to Create/Configure, not Delete-only * Fix: restrict ToolJet-DB proxy, join and export to authorized workspace access * Fix: drop removed JOIN_TABLES feature key from ToolJet-DB ability * chore: point server/ee at the ee release merge with main The main merge took server/ee from main (68e25c06), which drops the release's ee fixes (#870, #888, #912, #965). Point it at 866316de, the ee-server merge of main into the release branch. * fix: connect the sample data source as a restricted role Provision a tooljet_sample_* role on startup with SAMPLE_PG_DB_USER (or PG_USER) and point every sample data source at it. If the role can't be set up, sample queries are disabled instead of using the admin user. Role setup and populate-sample-db share one advisory lock so a table rebuild can't interrupt the grants. * chore(deps): fix high-severity vulnerabilities in frontend dependencies (#18646) Resolves all open high-severity Dependabot alerts for frontend/package-lock.json and the remaining high findings from npm audit. - Bump axios to ^1.20.0, dompurify to ^3.4.17, postcss to ^8.5.18, lodash to ^4.18.1, flatted to ^3.4.4 and webpack-dev-server to ^5.2.7 (drops node-forge via selfsigned 5) - Replace react-spring with @react-spring/web, removing react-native, metro, image-size and old ws copies from the tree - Bump form-data peer range in plugins to ^4.0.6 - Add overrides where upstream ranges block a patched version: brace-expansion (minimatch@3), immutable (draft-js), webpack-dev-middleware (storybook builder) and serialize-javascript - Refresh remaining transitive deps within their existing ranges * Fix: stricter TJDB bulk writes, Python sandbox and plugin loading (#18553) * fix: stricter TJDB bulk write column checks and Python sandbox fallback ToolJet Database bulk update and upsert accept only existing columns and quote column names with escapeIdentifier. Workflow Python steps are refused when nsjail is missing unless TOOLJET_WORKFLOW_SANDBOX_BYPASS=true. * fix: only load marketplace plugins by validated id Remove the unused GitHub repo fetch path for marketplace plugins so plugin code can only come from the ToolJet marketplace, and reject plugin ids that are not plain identifiers before they are used to build download URLs or local file paths. * Fix/restapi metadata secret redaction security (#18701) * fix: redact resolved secrets from query execution metadata * fix: complete query-metadata secret redaction (EE, plugin test, spec) Follow-on to the cherry-picked CE fix that redacts resolved {{secrets.*}} from query execution metadata. Brings the fix to the EE path and keeps the build and tests green: - bump server/ee to the EE scrub commit (runQuery + resolveConstants), so the redaction also applies on EE/Cloud where runQuery is fully overridden - move the redactHeaders plugin test from .ts to .js: a .ts test under the common package breaks its tsc -b build (file outside rootDir: lib) - update the util.service resolveConstants call assertions for the new optional collectedSecretValues argument Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Pratush <pratush@Pratushs-MBP.lan> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Security fix for main advisories * Fix: require a password on the bundled Redis * High vulnerabilities in plugin is resolved (#18728) * fix: resolve high-severity Dependabot alerts in marketplace (#18705) Regenerate the marketplace lockfile from scratch, upgrade lerna to v10 and add overrides for transitive packages pinned to vulnerable versions (follow-redirects, zod, smol-toml, undici, tmp); raise the axios floor to 1.20.0. Pin the hoisted @types/node to the 25 line, as on main, because v26 types do not parse under TypeScript 4.9. Regenerate the plugins/common lockfile so brace-expansion resolves to 1.1.21. * Fix: Patch high-severity advisories in server dependencies (#18704) * fix(deps): patch high-severity advisories in server dependencies Raise minimum versions: compression, joi, undici. Upgrade nodemailer 9 -> 10 (needs Node 20+; the server runs Node 22). Align the Nest framework packages (common, core, platform-express, platform-ws, websockets, microservices, testing) to 11.2.8. multer 2.4+ reworded an error message that Nest 11.1 matched on, which turned a wrong-field upload from 400 into 500; Nest 11.2 maps by error code. @nestjs/microservices 11.2 also does not load next to core 11.1. Raise override floors: @grpc/grpc-js, brace-expansion, fast-uri, multer, js-yaml. Add scoped overrides: mailparser and preview-email use nodemailer ^10, mailparser uses linkify-it ^5.0.2 (it pins an exact version), and postcss-parent-selector uses postcss ^8.5.18 (removes the nested postcss 5 copy). Refresh the lockfile for @xmldom/xmldom, body-parser, browserslist, source-map-js and form-data, whose fixes are inside existing ranges. Docker: install joi 17.13.8 instead of 17.4.1 in six images, so the image no longer replaces the patched copy with the old one. Alerts with no upstream fix are not part of this change. * fix(deps): update node-forge to 1.4.1 node-forge 1.4.1 requires a canonical DER DigestInfo when verifying RSA PKCS#1 v1.5 signatures. It is inside the existing ^1.3.1 range required by google-p12-pem, so only the lockfile changes. * chore(deps): raise joi pin in cypress test images to 17.13.8 Matches the runtime images and the server lockfile, so the test images no longer install the old joi. * chore: point server/ee at an existing commit The pointer inherited from release referenced a commit that no longer exists in the submodule remote, so image builds failed at the submodule update step. Point it at the commit that contains the same change on the submodule's release branch. * fix(deps): upgrade AI SDK to v5 and zod to 4.6 zod 3 carries a high-severity advisory and the AI SDK v4 requires zod 3, so both move together. - Raise ai to 5.0.x, the @ai-sdk providers to 2.x and zod to 4.6.7. - Override undici under @ai-sdk/provider-utils to 7.30.1, because v5 pins undici 5, which has open advisories. - Point server/ee at the matching agent node migration. * chore: point server/ee at the agent node model lookup fix Moves the pointer to the commit that also fixes the AI model lookup, which asked for a relation the data source entity no longer has. * Fix: bound Redis job retention and in-memory cache growth (#18703) * fix: bound Redis job retention and in-memory cache growth - Default BullMQ job retention for queues and jobs that set none, so finished jobs no longer stay in Redis forever. - Add an age limit to workflow job retention; each job holds the full run result. - Give in-memory cache entries a 5-minute default expiry and cap the store at 1000 entries, so keys that are never read again (OAuth authorization codes) no longer accumulate for the life of the process. * chore: update submodule pointers * revert: keep count-only workflow job retention An age limit does not lower peak Redis use; the count already caps it. --------- Co-authored-by: gsmithun4 <gsmithun4@gmail.com> * Fix: update snowflake-sdk and lerna dependencies in package-lock.json (#18765) * Fix/docs high dependabot alerts v3.21.80 beta (#18762) * fix(docs): bump body-parser to 1.20.9 to resolve high-severity DoS alert * fix(docs): bump launch-editor to 2.14.2 to resolve high-severity alert * fix(docs): bump follow-redirects to 1.16.2 to resolve high-severity alerts * fix(docs): bump source-map-js to 1.2.2 to resolve high-severity alert * fix(docs): bump compression to 1.8.2 to resolve high-severity alert * fix(docs): bump brace-expansion to 1.1.21 and 2.1.7 to resolve high-severity alerts * fix(docs): bump joi to 17.13.9 to resolve high-severity alert * fix(docs): bump fast-uri to 3.1.9 to resolve high-severity alerts * fix(docs): bump image-size to 2.0.4 to resolve high-severity alerts * fix(docs): bump js-yaml to 4.3.2 to resolve high-severity alert * fix(docs): bump svgo to 3.3.5 to resolve high-severity alert * fix(docs): bump nanoid to 3.3.20 to resolve high-severity alert --------- Co-authored-by: Pratush <pratush@Pratushs-MBP.lan> Co-authored-by: Pratush <pratush@Pratushs-MacBook-Pro.local> * fix(cli): resolve high-severity Dependabot alerts in CLI lockfile (#18771) Upgrade mocha from 9 to 10 so it no longer pins js-yaml 4.1.0, drop the nanoid override that only existed for mocha 9, and refresh the lockfile so every package flagged by Dependabot resolves to a patched version. * Fix: Send git-sync failure notification on every failed run (#18800) * Fix: send git-sync failure notification on every failed run * Bump server/ee: trim git-sync dedupe fix * fix: authorize resource export per resource type (#18848) Export now needs create + edit on each requested resource, checked against that type's own permissions: apps (app-create + edit), workflows (workflow-create + edit), modules (module-create + edit). View access no longer allows export, matching the dashboard's Export option. Every app in the body is checked, not only the first, and ids outside the caller's workspace are denied. ToolJet Database table export follows the table-metadata view rule (admin, builder or tjdb CRUD) instead of requiring app-create. The cross-workspace table export spec now expects 201 with no table: the controller forces the session workspace, so the foreign table is skipped rather than rejected. * fix: do not update invited accounts from the public instance signup path (#18851) An invited user who goes through the public signup page now only gets the activation link re-sent. Their account is no longer modified by that request, so the password is always set by whoever opens the link. Remove the unused updateExistingUserDefaultWorkspace helper and add a regression test. * CI: Unblock release v3.21.80-beta server build and vulnerability gate (#18875) * chore: update submodule pointers * fix: unblock release CI — sync server lockfile, keep CE-only scoping spec public The server lockfile had lost the mjml/html-minifier optional dependency tree, so npm ci failed. The workspace-scoping spec ran an EE row in the public test tree, which check-ee-leak.sh rejects; the EE row now lives in ee/test. * chore: update submodule pointers * fix: clear release vulnerability gate blockers in server and plugins Bump the plugins toml override to ^5.0.1 (snowflake-sdk, its only consumer, already asks for ^5). Drop the unused mjml and html-minifier optional dependencies from the server; nothing references them and html-minifier has no patched release. * fix: repair plugins lockfile so built plugins resolve their dependencies The lockfile had lost the proxy-agent entry @databricks/sql needs, and had mariadb, mysql2 and nodemailer nested under their workspace packages instead of hoisted. plugins/dist resolves from plugins/node_modules, so server migrations failed with MODULE_NOT_FOUND. * fix: override basic-ftp to ^6.2.5 in plugins Restoring proxy-agent for @databricks/sql pulled in basic-ftp 5.3.1 through pac-proxy-agent and get-uri, which has a HIGH advisory (<=6.2.0). get-uri's latest release still asks for ^5, so override it; every Client method get-uri calls exists in 6.x. * fix: override proxy-agent to ^6.5.0 for @databricks/sql proxy-agent 8 is ESM-only. Node's require() loads it, but Jest's module loader can't, so every server suite that loads plugins/dist failed with "Cannot use import statement outside a module". 6.x is CommonJS and is what @databricks/sql itself asks for; the basic-ftp override still covers its chain. * test: give data sources distinct names in data-queries specs Data source names are unique per workspace branch, so two apps seeded in one workspace collided. Cherry-picked from a1ee618 (#18719), without its import-export hunk, which passes as-is on this branch. * chore: update submodule pointers * test: catch CE specs up with release-line security fixes - Route inventories: dependent-queries now uses :id, and the ToolJet DB join route is gone. - ToolJet DB isolation: seed workspace B's environments (table create reads them), and drop the committed seed in afterAll. Its leftover workspaces have signup off and became the instance's oldest workspace, so later CE specs in the same worker got 403 on signup. * chore: update submodule pointers --------- Co-authored-by: Shantanu Mane <maneshantanu.20@gmail.com> * fix: expose MessagePort and DOMException to marketplace plugins Marketplace plugins run in a vm context built from `...global`, which only copies enumerable properties. MessagePort, MessageChannel and DOMException are non-enumerable in Node, so plugins bundling undici 7 (Qdrant's REST client since the marketplace lockfile regeneration) failed at load with "MessagePort is not defined" on every operation. * fix(cli): resolve remaining high/critical Dependabot alerts in CLI lockfile (#18914) Prune the stale mocha/nanoid entry left after the mocha 10 upgrade, apply npm audit fix, and override tmp and serialize-javascript. Co-authored-by: Pratush <pratush@Pratushs-MBP.lan> * fix: require create access to export modules and ToolJet Database tables (#18909) Module export (POST /api/modules/export) let any builder export, even without module-create. It now needs module-create plus edit on each requested module, rejects ids that are not modules in the workspace, and requires tjdbCRUD when tables are included. ToolJet Database table export on /v2/resources/export no longer lets every builder through; non-admins need tjdbCRUD. * list api search params issue fixed (#18928) * Update subproject commits for frontend and server components * Bump version to 3.21.94-beta for all components --------- Co-authored-by: Shantanu Mane <maneshantanu.20@gmail.com> Co-authored-by: Pratush <pratush@Pratushs-MacBook-Pro.local> Co-authored-by: Rudhra Deep Biswas <rudra21ultra@gmail.com> Co-authored-by: Pratush <pratush@Pratushs-MBP.lan> Co-authored-by: gsmithun4 <gsmithun4@gmail.com> Co-authored-by: Pratush Sinha <104584767+Pratush613@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Adish M <44204658+adishM98@users.noreply.github.com> Co-authored-by: Akshay Sasidharan <akshaysasidharan93@gmail.com> Co-authored-by: Johnson Cherian <johnsonc.dev@gmail.com> Co-authored-by: Akshay <akshaysasidrn@gmail.com> Co-authored-by: Souvik <psouvik260@gmail.com> Co-authored-by: Adish M <adish.madhu@gmail.com> Co-authored-by: Ganesh Kumar <40178541+ganesh8056@users.noreply.github.com> Co-authored-by: Rudhra Deep Biswas <98055396+rudeUltra@users.noreply.github.com> Co-authored-by: johnsoncherian <57667706+johnsoncherian@users.noreply.github.com> Co-authored-by: Shaurya Sharma <shaurya064@gmail.com> Co-authored-by: Nakul Nagargade <nakul@tooljet.com> Co-authored-by: manishkushare <kushare.manish9@gmail.com> Co-authored-by: Vijaykant Yadav <vjy239@gmail.com> Co-authored-by: devanshu052000 <devanshu.rastogi05@gmail.com> Co-authored-by: ajith-k-v <ajith.jaban@gmail.com> Co-authored-by: rudrapratik30 <pratik104agrawal@gmail.com> Co-authored-by: Yukti Goyal <yuktigoyal02@gmail.com> Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> Co-authored-by: Arnav Maggon <arnavmaggon2005@gmail.com> Co-authored-by: Swathi Hameed <42898362+swathihameed@users.noreply.github.com> Co-authored-by: Shaurya Sharma <79473274+shaurya-sharma064@users.noreply.github.com> Co-authored-by: gsmithun4 <3417097+gsmithun4@users.noreply.github.com> Co-authored-by: Ganesh Kumar <ganesh8056234@gmail.com> Co-authored-by: Madhav Jha <jhamadhav28@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Fix: App loads exhausting the DB pool via per-app hydration (#18884) * fix: use COUNT in app license guards to avoid pool exhaustion AppCountGuard and ResourceCountGuard loaded every App entity with manager.find + relations just to compare the total against the license limit. Each loaded App fires AppsSubscriber.afterLoad, which opens its own transaction (GitSyncConfigsUtilService.getDetails + version lookup, hitting organization_git_sync_branches). One create request therefore held 1 outer pool connection plus N inner ones, exhausting PG_POOL_MAX (25) once 25+ front-end apps existed and failing creates with 500 "timeout exceeded when trying to connect". Use manager.count with the same where-condition instead. COUNT never instantiates entities, so no subscriber runs and pool use stays flat regardless of app count. * fix: use COUNT in role-downgrade ownership check to avoid pool exhaustion Same pattern as the app license guards: checking whether a user owns any apps loaded every App entity via manager.find just for a length check, firing per-row afterLoad work in separate transactions. At scale this exhausts the DB pool the same way. Use manager.count for the gate. App names for the 400 error payload are fetched only on the error path via a raw names-only query, which never instantiates entities. Success and ownership-transfer paths are unchanged. * test: pin single-COUNT app counting in license guards Add a unit spec asserting both license guards count apps via a single manager.count call and never load entities via find. Restoring find fails the spec. Also record the never-find-to-count-App rule in the licensing module docs. * fix: use raw queries for module lookups in app import/export Two module lookups instantiated full App entities while reading only id and co-relation-id columns, firing per-row afterLoad work in separate transactions. Raw selects return the same rows with no entity instantiation. Downstream readers only ever used those two columns. * fix: skip per-row app hydration in sample-app and import listing loads * chore: update submodule pointers * fix: stop per-version app hydration starving the DB pool on slug lookups GET /api/session?appId=<slug> and GET /api/apps/app-authentication-config/<slug> loaded one App entity per matching default-branch version row. AppsSubscriber.afterLoad then ran gitSyncConfigsUtilService.getDetails for each App in parallel, each on its own pooled connections while the loading query still held one. Apps with ~12+ versions exhausted a 25-connection pool inside a single request and failed after the 5s pg-pool connect timeout. Neither caller reads the hydrated fields, so both now opt out via skipAppEditingVersionHydration, and retrieveAppDataUsingSlug fetches a single row. The AsyncLocalStorage moves to its own file so AppsRepository can import it without an import cycle; the subscriber re-exports it. * chore: bump version to 3.21.91-beta * fix: stop app afterLoad hydration taking extra DB connections AppsSubscriber.afterLoad runs for every loaded App in parallel while the loading query still holds its connection. It called getDetails (own transaction) and an AppVersion lookup on fresh pooled connections, so any query loading many Apps could exhaust the pool and fail after the 5s connect timeout. afterLoad now passes TypeORM's LoadEvent.manager, bound to the loading connection, to getDetails and uses it for the AppVersion lookup. getDetails accepts an optional manager and runs its reads on it. getAllGranularPermissions also skips the hydration, since it loads one App per individually granted app and its callers only read app columns. * fix: fall back to apps.name when listing owned apps on role downgrade Apps without a non-stub version row (or with no app_name on it) were reported by id in the "owner of apps" error. Keep apps.name ahead of the id fallback, matching the previous behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: update version to 3.21.93-beta across all components --------- Co-authored-by: Shantanu Mane <maneshantanu.20@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Fix: Guard slug lookups exhausting the DB pool for apps with many ver… …sions (#18885) * fix: limit guard slug lookups to one app to stop pool exhaustion findAppBySlug, findBySlug and findByAppName matched every default-branch version row of an app and loaded one App per row, each running AppsSubscriber.afterLoad on its own pooled connection. Apps with many versions exhausted the pool and validate-released-app-access (and other slug-guarded routes) timed out. LIMIT 1 keeps hydration but for one App. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: bump version to 3.21.92-beta --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Fix: Slug lookups exhausting the DB pool for apps with many versions (#… …18883) * fix: stop per-version app hydration starving the DB pool on slug lookups GET /api/session?appId=<slug> and GET /api/apps/app-authentication-config/<slug> loaded one App entity per matching default-branch version row. AppsSubscriber.afterLoad then ran gitSyncConfigsUtilService.getDetails for each App in parallel, each on its own pooled connections while the loading query still held one. Apps with ~12+ versions exhausted a 25-connection pool inside a single request and failed after the 5s pg-pool connect timeout. Neither caller reads the hydrated fields, so both now opt out via skipAppEditingVersionHydration, and retrieveAppDataUsingSlug fetches a single row. The AsyncLocalStorage moves to its own file so AppsRepository can import it without an import cycle; the subscriber re-exports it. * chore: bump version to 3.21.91-beta
Feature: OIDC group sync with nested claims and a delimiter (lts-3.16) ( #18799) * feat: add delimiter column and OIDC group sync tests Adds a nullable delimiter column to sso_config_oidc_group_sync and the matching entity field, used by the nested-claim and delimiter handling in the EE OIDC service. Adds unit tests for dot-path claims, delimiters and the groups scope rule, plus an e2e login flow driven by a small mock OIDC IdP. * chore: update submodule pointers * chore: move OIDC group sync tests to the EE test tree The tests exercise EE code, so they now live under server/ee/test. The e2e config adds that tree as a root when the submodule is present, so community clones without it still run unchanged. * chore: update submodule pointers * chore: bump version to 3.20.255-lts --------- Co-authored-by: gsmithun4 <gsmithun4@gmail.com>
PreviousNext