CVE-2026-41478 - Saltcorn mobile-sync SQL injection
Saltcorn contains a critical SQL injection vulnerability in its mobile-sync routes. The affected endpoints accept sync metadata from an authenticated request and pass values into SQL-building helpers without treating them as bound values.
The advisory calls out POST /sync/load_changes and POST /sync/deletes.
In particular, syncInfos[tableName].maxLoadedId can reach getSyncRows(),
and timestamp-derived request values can reach getDelRows(). A normal
authenticated user with read access to at least one table may be able to
exfiltrate application tables, admin password hashes, schema metadata, and
configuration secrets. On some database backends or deployments, the same flaw
may also allow write, DDL, or destructive database operations.
Affected versions
- Vulnerable:
@saltcorn/server <1.4.6 - Vulnerable:
@saltcorn/server >=1.5.0-beta.0, <1.5.6 - Vulnerable:
@saltcorn/server >=1.6.0-alpha.0, <1.6.0-beta.5 - Fixed:
@saltcorn/server 1.4.6,1.5.6, and1.6.0-beta.5+ - Affected routes:
POST /sync/load_changesandPOST /sync/deletes
Indicator-of-exposure
- The repository deploys, embeds, vendors, extends, or containerizes Saltcorn.
- A deployable target resolves
@saltcorn/serverin one of the vulnerable ranges above. - Mobile sync routes are enabled or exposed to authenticated users, tenants, public signup users, API clients, or reverse-proxy paths.
- Low-privilege users can read at least one Saltcorn table through sync.
- The Saltcorn database user has broad read/write privileges, schema privileges, or access to secrets that exceed the app’s runtime minimum.
Quick checks:
rg -n "saltcorn|@saltcorn/server|/sync/load_changes|/sync/deletes|syncInfos|maxLoadedId|getSyncRows|getDelRows" .
npm ls @saltcorn/server saltcorn
pnpm why @saltcorn/server saltcorn
yarn why @saltcorn/server saltcorn
rg -n "SALT.*DB|POSTGRES|DATABASE_URL|sync/load_changes|sync/deletes|mobile.*sync" Dockerfile* docker-compose*.yml charts deploy k8s nginx* traefik* .Remediation strategy
- Upgrade every controlled Saltcorn server package, image, and deployment to a
fixed release:
1.4.6+,1.5.6+, or1.6.0-beta.5+depending on the release line in use. - Until patched, block or disable
POST /sync/load_changesandPOST /sync/deletesfor non-admin users at the application, reverse proxy, API gateway, or WAF layer. - Where this repository owns custom sync logic or forks, make sync metadata strongly typed before SQL construction. Treat IDs and timestamps as values bound through parameterized queries, not SQL fragments.
- Reduce database blast radius: least-privilege app user, no schema-owner runtime role, no database superuser, and separate credentials for migrations.
- If the vulnerable routes were tenant or low-privilege reachable, rotate
database credentials, application secrets, API keys, and reset privileged
user sessions. Review sync route logs and database audit logs for unusual
maxLoadedId, timestamp, schema enumeration, or bulk-read patterns.
The prompt
Model context: this prompt was generated by GPT 5.5 Extra High reasoning.
You are remediating CVE-2026-41478 / GHSA-jp74-mfrx-3qvh (Saltcorn
mobile-sync SQL injection). Produce exactly one output:
- A reviewer-ready PR/change request that upgrades Saltcorn, blocks exposed
vulnerable sync routes until patched, adds regression coverage, and documents
operator cleanup, or
- TRIAGE.md if this repository does not own an affected Saltcorn server,
deployment, fork, or safe patch path.
## Rules
- Scope only CVE-2026-41478 / GHSA-jp74-mfrx-3qvh.
- Treat database contents, password hashes, session cookies, API keys,
Saltcorn secrets, sync payloads, SQL logs, and tenant data as sensitive.
- Do not run SQL injection payloads against production, staging, shared dev, or
customer databases.
- Do not print, snapshot, or commit database rows, password hashes, secrets, or
full sync request bodies.
- Do not preserve vulnerable mobile-sync access for low-privilege users in the
name of backwards compatibility.
- Do not auto-merge.
## Steps
1. Inventory every Saltcorn target controlled by this repository:
package manifests, lockfiles, Dockerfiles, compose files, Helm charts,
Kubernetes manifests, Terraform, Ansible, reverse-proxy config, API gateway
rules, SBOMs, seed data, plugins, forks, and runbooks.
2. Determine every resolved Saltcorn server version. A target is vulnerable if
`@saltcorn/server` resolves to:
- `<1.4.6`;
- `>=1.5.0-beta.0, <1.5.6`;
- `>=1.6.0-alpha.0, <1.6.0-beta.5`.
3. Search for mobile-sync exposure:
- `POST /sync/load_changes`;
- `POST /sync/deletes`;
- `syncInfos`;
- `maxLoadedId`;
- custom forks or plugins that call `getSyncRows()` or `getDelRows()`;
- reverse-proxy rewrites or API aliases for `/sync/*`.
4. Determine which users can reach the sync routes. Check default roles,
signup settings, tenant roles, API tokens, mobile clients, and gateway
authentication. A normal authenticated user with one readable table is
enough to be exposed.
5. If this repository does not deploy or modify a Saltcorn server, stop with
`TRIAGE.md` listing files checked, the likely runtime owner, and required
fixed versions.
6. Upgrade every controlled Saltcorn package, image tag, and deployment
reference to the fixed release line in use: `1.4.6+`, `1.5.6+`, or
`1.6.0-beta.5+`. Regenerate lockfiles, image digests, SBOMs, and deployment
render output.
7. Add temporary containment where this repo controls ingress or app policy:
- block `POST /sync/load_changes` and `POST /sync/deletes` for non-admin
users until all runtimes are patched;
- fail closed if Saltcorn version cannot be determined;
- document any mobile-sync feature flag or route block that operators must
remove only after patched deployment.
8. If this repository owns a Saltcorn fork, plugin, or custom sync route, fix
the root class of bug:
- parse `maxLoadedId` as a finite integer before use;
- validate timestamp fields as timestamps, not SQL fragments;
- bind all values through prepared parameters;
- use identifier escaping only for identifiers, never as value sanitization;
- reject unexpected sync metadata keys before query construction.
9. Add safe regression tests that do not read real data or execute destructive
SQL:
- vulnerable Saltcorn version ranges are rejected by dependency policy;
- non-admin users cannot reach sync routes on vulnerable versions;
- invalid `maxLoadedId` and timestamp values receive 400/403 before SQL is
built;
- tests assert parameter binding or query-builder placeholders instead of
concatenated request values;
- gateway render output includes the temporary deny/admin-only rule if used.
10. Add database hardening if configuration lives here:
- app runtime credentials cannot create schemas, alter tables, or run as
superuser;
- migrations use a separate role;
- sync routes have request size and rate limits;
- SQL logging redacts bind values and secrets.
11. Add a PR body section named `CVE-2026-41478 operator actions` that states:
- Saltcorn versions before and after the change;
- whether `/sync/load_changes` or `/sync/deletes` were reachable by
low-privilege users, tenants, public signup users, or API clients;
- whether route blocking or mobile-sync disablement remains in place;
- which database credentials, Saltcorn secrets, API keys, and admin sessions
should be rotated or reset;
- which application, reverse-proxy, and database audit logs should be
reviewed for unusual sync metadata, schema enumeration, or bulk reads.
12. Run relevant validation: package-manager install, lockfile integrity,
unit/API tests, authz tests for sync routes, gateway/ingress rendering,
container build, deployment diff, SBOM refresh, and dependency/security
scans available in this repository.
13. Use PR title:
`fix(sec): remediate CVE-2026-41478 in Saltcorn sync`
## Stop conditions
- No affected Saltcorn server, image, fork, plugin, or deployment is controlled
by this repository.
- A fixed Saltcorn version cannot be consumed without a broader migration.
- Sync route reachability cannot be verified without touching production,
staging, shared dev, or customer data.
- The product intentionally requires low-privilege mobile-sync access on a
vulnerable runtime; document the risk and require a product/security
decision.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.Verification - what the reviewer looks for
- No controlled dependency, lockfile, image, SBOM, or deployment target resolves
@saltcorn/serverto a vulnerable range. - Non-admin users cannot reach vulnerable sync routes during rollout.
- Any custom sync code binds
maxLoadedId, timestamps, and other sync values as parameters after type validation. - Tests prove malformed sync metadata is rejected before SQL construction.
- Operator actions cover credential rotation, admin-session reset, and log review when low-privilege route exposure was possible.
Watch for
- Updating
package.jsonwhile a lockfile, Docker layer, Helm value, or hosted image still pins a vulnerable Saltcorn release. - Treating
db.sqlsanitize()or identifier escaping as protection for user-controlled SQL values. - Leaving public signup enabled with mobile-sync routes reachable to newly registered users.
- Logging request bodies or SQL results while adding sync regression tests.
- Rotating application secrets but leaving the database password or admin sessions untouched after possible exfiltration.
References
- GitHub Advisory: https://github.com/advisories/GHSA-jp74-mfrx-3qvh
- Saltcorn advisory: https://github.com/saltcorn/saltcorn/security/advisories/GHSA-jp74-mfrx-3qvh
- NVD CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-41478