🚀 DAY 5 OF LAUNCH WEEK: Introducing Socket Firewall Enterprise.Learn more →
Socket
Book a DemoInstallSign in
Socket

sails-hook-waterline-safe-criteria

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sails-hook-waterline-safe-criteria

Sails hook that guards Waterline queries against undefined where-clause values and missing criteria.

latest
Source
npmnpm
Version
0.1.2
Version published
Weekly downloads
10
100%
Maintainers
1
Weekly downloads
 
Created
Source

sails-hook-waterline-safe-criteria

Guard Sails/Waterline queries from silently matching everything when unsafe criteria slip through (e.g. undefined in a where clause or calling Model.destroy() with no filters).

Socket Badge

Key points

  • Secure by default: once installed the guard is active unless you explicitly disable it.
  • Per-model overrides let you keep legacy behavior where needed.
  • Per-query bypass is available by including meta: { allowUndefinedWhere: true } alongside your criteria.

Why this hook exists

Waterline 0.15 keeps backwards compatibility by stripping undefined values from criteria. In destructive operations that turns this:

await User.destroy({ where: { status: undefined } });

into User.destroy({}) and deletes every record.

sails-hook-waterline-safe-criteria adds a guard without forking Waterline. The hook is secure by default; you can opt out globally, per model, or on individual queries when you really need the legacy behavior.

Requirements

DependencyRequirement
Sails≥ 1.0.0
Waterline0.15.x (bundled with Sails 1.x)
Node.js≥ 14 (tests run on 16+)

The hook inspects stage-one criteria, so it works with any adapter (sails-disk, sails-mongo, sails-postgresql, custom adapters, etc.).

Local development

  • Install dependencies: npm install.
  • Run the unit/integration suite with npm test.
  • Ensure Docker is available if you plan to exercise the adapter matrix (npm run test:adapters).
  • Use npm run test:all before sending changes to cover every scenario.

Installation

npm install sails-hook-waterline-safe-criteria --save

Sails auto-loads any dependency named sails-hook-*. If you prefer to be explicit (or to customize the config key) add the hook to config/hooks.js:

module.exports.hooks = {
  'waterline-safe-criteria': require('sails-hook-waterline-safe-criteria')
};

Configuration

ScopeSettingEffect
Globalconfig/models.js → rejectUndefinedWhere (default: true)Secure-by-default. Set to false if you intentionally want legacy behavior.
Per modelapi/models/Order.js → rejectUndefinedWhere: trueOpt in for specific models only (inherits the global default otherwise).
Hook defaultsconfig/waterline-safe-criteria.js → { enabled: false }Optional: explicitly opt out of the default guard for the whole app.

Per-query bypass

Legacy code paths can still opt in to the old behavior (or you can disable the guard globally by setting config.models.rejectUndefinedWhere = false). Add a meta object to your stage-one criteria when you really need to bypass the undefined check:

await Order.destroy({
  where: criteria,
  meta: { allowUndefinedWhere: true }
});

The guard still requires criteria to exist, but it ignores undefined values when that meta flag is present. The original meta object is reattached to Waterline’s Deferred so adapter-level features (.meta({ fetch: true }), etc.) keep working.

What the guard does

After sails-hook-orm loads, the hook wraps these helpers on every guarded model:

find, findOne, destroy, destroyOne, update, updateOne, count, sum, avg

Each call goes through the following checks:

  • Criteria must be supplied (no bare Model.destroy() / Model.update()).
  • Any undefined inside the where clause—including nested and/or/in structures—is rejected.
  • Criteria objects are not mutated; the hook works with Promises or old-school Deferreds alike.

If an unsafe pattern is detected the guard throws a flaverr with code E_UNDEFINED_WHERE. Example messages:

Unsafe DESTROY on `user` would hit every record. Pass an explicit WHERE or include `meta: { allowUndefinedWhere: true }` to bypass intentionally.
Unsafe UPDATE on `order` detected undefined inside WHERE clause. Undefined values cause Waterline to remove predicates and match everything. Scrub the criteria first, or bypass with `meta: { allowUndefinedWhere: true }`.

Migration tips

  • Enable in staging first. Turn on rejectUndefinedWhere globally and run your test suite. Any unsafe queries now fail early.
  • Fix or bypass intentionally. Clean up the criteria or add meta: { allowUndefinedWhere: true } where the behavior is desired.
  • Roll out per model if needed. Leave legacy models unguarded (rejectUndefinedWhere: false) while protecting everything else.

Behavior summary

  • Throws when criteria are missing (even with bypass meta).
  • Accepts primary-key shorthand (Model.find(7) or Model.destroy([1,2])).
  • Catches undefined inside nested predicates and arrays.
  • Supports meta: { allowUndefinedWhere: true } to bypass only the undefined-value check.
  • Keeps Deferred helpers (.meta, .fetch) intact.

Example

// Before (legacy behavior wipes everything)
await User.destroy({ where: { status: undefined } });

// After enabling the hook (throws E_UNDEFINED_WHERE)
await User.destroy({ where: { status: undefined } });

// If you really need the legacy behavior:
await User.destroy({ where: { status: undefined }, meta: { allowUndefinedWhere: true } });

Testing

Run the core unit + integration suite:

npm test

Adapter coverage (MySQL, PostgreSQL, MongoDB) lives in a separate job because it depends on Docker:

npm run test:adapters

For everything at once, use:

npm run test:all

The suites verify the guard on every Waterline helper, nested criteria detection, meta bypass behavior, and three integration scenarios (guarded app, baseline app, per-model configuration). The adapter matrix re-runs the critical happy/sad paths against real adapters.

Adapter test matrix

A docker-compose file is included for local adapter testing, and the helper script bootstraps/tears down everything automatically:

npm run test:adapters

Under the hood the script starts the compose stack, waits for each service to be ready, exports the expected connection strings, runs the adapter spec, and shuts everything down. Nothing to configure.

Tip: npm run test:all chains the full suite. npm run test:adapters:raw runs just the adapter spec when you already have databases running.

VariableDescription
TEST_MYSQL_URLOverride MySQL connection string (defaults to compose stack).
TEST_POSTGRES_URLOverride PostgreSQL connection string (defaults to compose stack).
TEST_MONGO_URLOverride Mongo connection string (defaults to compose stack).

Limitations

  • Only stage-one criteria are inspected. Raw adapter calls or stage-two tweaks are unaffected.
  • The guard doesn’t attempt to rewrite unsafe queries; it simply throws so you can decide how to fix or bypass.
  • allowUndefinedWhere bypasses undefined checks but not the “criteria required” rule.

License

MIT © Luis Lobo Borobia

Keywords

sails

FAQs

Package last updated on 03 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts