Secure the inline column update routes - #18
Merged
Merged
Conversation
The resource and relation manager column update routes loaded records without tenant scoping, skipped update authorization, and wrote any requested attribute (the relation route with no check at all), so any panel user could change arbitrary attributes of records they may not edit. Both routes now go through ColumnStateController, which only writes an editable, non-disabled, non-relationship column of the relevant table, loads records through the resource's tenant-scoped query, enforces canUpdate()/policies (plus the relation manager's canEdit()), validates the value with the column's rules and writes only that attribute. Releases of laravilt/tables without EditableColumn fall back to allowing only ToggleColumn with a boolean value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 18 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
CI installs laravilt/tables 1.0.x, where the fallback only allows ToggleColumn, so select option validation cannot be exercised there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Vulnerability
PanelServiceProviderregistered two inline column update routes (used byToggleColumnin tables and relation managers, and by the card-gridToggleGridColumn):PATCH {slug}/{id}/columnloaded the record withfindOrFail(), which skips tenant scoping. It wrote to any column in the table config, including plainTextColumns. It never checked update authorization and never validated the value.PATCH {slug}/{id}/relations/{relationship}/{relationId}/columnwroterequest('column') => request('value')onto the related record with no check at all.As a result, any authenticated panel user could change arbitrary attributes (e.g.
is_admin, foreign keys) of records they are not allowed to edit, including records of other tenants.Fix
Both closures now delegate to a new
Laravilt\Panel\Http\Controllers\ColumnStateController. It mirrors the new laravilt/tables column endpoint (tables#11):table()(or the relation manager'stable()). It must be editable (EditableColumn), not disabled, and not a relationship path. Non-editable columns get 403; unknown columns get 404; a missing name gets 422.Resource::getEloquentQuery(). Related records are loaded through the relation manager's relationship query, so they must belong to that owner.canUpdate($record)(permissions, or the policy when$usePoliciesis set). For the relation route, the relation manager'scanEdit()must pass, the owner resource'scanUpdate($owner)must pass, and the related model'supdatepolicy must pass if one is registered.getStateValidationRules()(boolean for Toggle/Checkbox, allowed options for Select, plusrules()), thendehydrateState(). Errors are keyed by the column name, which is what the Vue columns read.beforeStateUpdated/afterStateUpdatedstill run.back()for Inertia; JSON for non-Inertia AJAX requests.Compatibility with laravilt/tables 1.0.x
Released tables versions do not have
EditableColumnor the new column methods. The controller checksinterface_exists(EditableColumn::class). When the interface is missing, onlyToggleColumnis editable, and the value must passrequired|boolean. All other checks (scoping, authorization, single-attribute write) still apply.Tests
tests/Feature/ColumnUpdateRouteTest.phpregisters the real route closures and covers:supportsEditableColumns().Full suite: 133 passed.
🤖 Generated with Claude Code