Safeguard
Security Guides•

How do you authorize list and search endpoints, not just single objects?

Checking GET by ID is not enough. List, search, export and count endpoints need the same rule. Three ways to enforce it and the traps in each.

Safeguard Security Team
4 min read

Authorize a collection by restricting what the query can return, not by checking items after you have loaded everything. Either filter in the data layer with the caller's tenant and permission predicates, or fetch a bounded set and check each item, and apply the same rule to counts, exports and aggregates.

Why lists get missed

Teams write a careful check for the single-document route and then ship GET /documents?q=report with a bare query on the collection. The OWASP Authorization Decisions and Output Handling Cheat Sheet says the restriction must cover every data path: list, search, export, count, aggregate and direct-object reads. An authorized list does not authorize a later update or delete either, so those still need their own checks.

A list endpoint is also where one bug leaks the most. A missing filter on a single-object route exposes one record per guess. On a list route it can expose a table.

Three ways to enforce it

The same cheat sheet describes three approaches. Pick by what your policy engine and data store really support.

ApproachHow it worksBest for
Check each candidateRetrieve a bounded set, evaluate each item, drop denied onesSmall sets, no filter interface
Fetch authorized IDsThe policy engine returns identifiers the caller may access, and you query only thoseWhen the engine can list permitted objects
Apply an authorization filterThe engine returns a predicate or query plan that the data layer enforcesLarge queryable collections

Check each candidate

Simple and flexible, but you have to bound the candidate set and keep it inside the trusted service until checks finish. Excluded and unresolved items must never leave. Pagination gets awkward, since a page of 50 may shrink to 12 after filtering.

Fetch authorized identifiers

The guidance warns that result limits and deadlines may apply. A truncated authorized subset can be shown as partial if every returned item is permitted, but it cannot prove the complete set. Never read an empty or incomplete list as permission to drop the restriction.

Apply a filter

The data layer enforces a predicate during retrieval. Use a maintained adapter for the exact engine and store, bind filter values as parameters, allow-list field names and operators, and reject translations you cannot represent. Do not silently omit an expression that failed to translate, and do not run a returned debug string as a query.

Rules that apply to all three

  1. Intersect predicates with logical AND. Authorization narrows the tenant and business filters, it never replaces them.
  2. Fail closed. If the policy engine errors or times out, deny. A missing filter is not an unrestricted result.
  3. Cover counts and totals. A "1,204 results" line leaks information about rows the caller cannot see.
  4. Cache only for the same subject, action, scope and tenant, within an approved freshness limit.
  5. Test with permitted and denied resources, tenant boundaries and incomplete results.

A quick way to test

Create two users with different access and seed records that only one may see. Call every list, search, export and count route as the other user and assert the response contains none of those records and the total matches the visible set. Run it again after a permission change.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how the scan treats collection endpoints next to single-object ones.

Safeguard supports dependency scanning, policies and gates for pull requests, so changes that touch your query or authorization libraries can be held for review. Try the free scan at gold.safeguard.sh/scan.

Quick check

Is filtering results in the UI enough?

No. The server must withhold the data. Anything sent to the browser can be read, whatever the page chooses to display.

Do export and CSV download routes need the same rule?

Yes. Exports are collections too, and they often run in background jobs that lose the caller's context unless you carry it through.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.