---
title: "Security model — Query Builder for Laravel | Roundly"
description: "How the package keeps request input away from SQL: allow-lists, bound values, escaped wildcards, request limits and capped error output."
url: https://roundly-consulting.com/open-source/docs/query-builder-for-laravel/security
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Query Builder for Laravel](https://roundly-consulting.com/open-source/docs/query-builder-for-laravel.md)

# Security model

The package sits between untrusted query strings and your database, so the dangerous parts are designed out rather than left to each endpoint:

- Allow-list by default — nothing is filterable or sortable unless declared; anything else is an HTTP 400 (or dropped in ignore mode). A mistyped mode config throws InvalidConfigurationException rather than guessing.
- Operators never come from raw input — operator() fixes the comparison in code; operators() honours only the tokens you declared and treats anything else as a literal value.
- Bound values, developer identifiers — built-in filters bind every value as a parameter; column identifiers come from your declarations and are wrapped by the query grammar, never from the request.
- Wildcards can’t widen a search — %, \_ and \\ in user input are escaped and matched with an explicit ESCAPE clause on every driver.
- Bounded work — limits.max\_filter\_values, limits.max\_value\_length and limits.max\_sorts cap what a single URL can ask for; duplicate sort columns are removed.
- No argument injection into scopes — a scope receives exactly one request-controlled argument unless you opt into spread: true.
- Capped reflection — error messages echo at most 5 unknown keys, each truncated to 64 characters.
- Typed columns stay safe — a FilterValueShape keeps malformed uuids and ids away from PostgreSQL, so a bad value is an empty result, not a 500.
- Validated page size — per\_page above the maximum is a 422, and perPage() hard-caps it again.
- Public names, private columns — internal names keep your schema out of the URL.

## Correct negations

Negations mean what a person filtering a list means: not and ncontains include NULL rows, a multi-value negation reads as “none of these” (AND, not OR), and relation negations use whereDoesntHave, so a row related to an excluded value is dropped even when it has other relations.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/query-builder-for-laravel.md)
