Skip to content

Validate sort/direction on index screens against SQL injection - #65

Merged
HafizMMoaz merged 1 commit into
mainfrom
fix/unvalidated-orderby-index
Jul 21, 2026
Merged

Validate sort/direction on index screens against SQL injection#65
HafizMMoaz merged 1 commit into
mainfrom
fix/unvalidated-orderby-index

Conversation

@HafizMMoaz

Copy link
Copy Markdown
Member

Closes #39.

Ten index() controllers ordered by orderBy(request('sort'), request('direction')) with the column taken straight from the query string. Eloquent binds values but not identifiers, so a crafted ?sort= reached the SQL text unescaped, a 500 at best and an injection surface at worst.

Fix

Every call site now uses the sortSafe query macro already shipped in v1.2.3 (zerp/account): it accepts a column only if Schema::hasColumn confirms it exists on the table, and a direction only if it is asc/desc, falling back to a safe default otherwise. No new code, the macro is registered globally and zerp/account is a hard dependency.

Each controller keeps its existing fallback and default direction, including UserController's demo/superadmin ordering and OrderController's id desc. Only invalid input changes: from a 500 or injection to a safe order.

Verified locally

  • tinker: sortSafe("id; DROP TABLE users", ...) compiles to order by \id` asc`; a valid column passes through.
  • Real authed request to /users?sort=id;DROP TABLE users-- returns 200 (was a 500/injection surface); valid ?sort=email&direction=desc returns 200; users table intact.

Module packages (account already done, plus budget-planner, contract, double-entry) carry the same pattern in their own repos and are tracked separately.

Ten index controllers ordered by a column and direction taken straight
from the query string: orderBy(request('sort'), request('direction')).
Eloquent binds values but not identifiers, so the column name reached the
SQL text unescaped. A crafted ?sort= was at best a 500 from a non-existent
column and at worst an injection surface.

Every call site now uses the sortSafe query macro shipped in v1.2.3
(zerp/account), which only accepts a column that exists on the table
(Schema::hasColumn) and a direction of asc or desc, falling back to a safe
default otherwise. Each existing fallback and default direction is
preserved, including UserController's demo/superadmin ordering, so only
invalid input changes behaviour: from a 500 or injection to a safe order.

Closes #39
@HafizMMoaz
HafizMMoaz requested a review from a team as a code owner July 21, 2026 01:46
@HafizMMoaz
HafizMMoaz merged commit c93eba9 into main Jul 21, 2026
1 check passed
@HafizMMoaz
HafizMMoaz deleted the fix/unvalidated-orderby-index branch July 21, 2026 11:11
@HafizMMoaz HafizMMoaz mentioned this pull request Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[zerp] Unvalidated orderBy(sort/direction) across index controllers (SQL injection surface)

1 participant