GHSA-8fq9-273g-6mrg: Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation
SummaryA critical missing authorization flaw exists in Avo's association attach workflow. The UI and `GET /resources/:resource/:id/:related/new` path can check `attach_<association>?`, but the actual write endpoint, `POST /resources/:resource/:id/:related`, does not run the same authorization check before mutating the association.As a result, an authenticated low-privileged Avo user can bypass hidden/disabled attach controls and directly attach related records to a parent record by sending a crafted POST request. In applications where associations represent teams, tenants, roles, projects, users, memberships, ownership, or other authorization-bearing relationships, this can lead to privilege escalation and cross-tenant data exposure.DetailsThe association attach route writes relationships through `Avo::AssociationsController#create`:The controller registers an attach authorization callback only for `new`, not for `create`:The `new` action is only the form-rendering step. The actual mutation happens in `create`:`create_association` then attaches the attacker-supplied related record to the parent:The only attach-specific authorization helper is:Because this helper is bound only to `new`, a policy that denies `attach_users?`, `attach_teams?`, `attach_roles?`, or similar methods blocks the UI/form path but does not protect the write path.This is inconsistent with the detach path, which does authorize the mutating `destroy` action:The bug is especially dangerous because Avo already treats association authorization as an access-control boundary in UI components:However, server-side enforcement is missing on the actual attach POST endpoint.Proof of ConceptPrerequisites:A Rails application mounts Avo, for example at `/admin`.Avo authorization is enabled.A low-privileged user can authenticate to Avo.A parent record and a related record are both reachable by ID.The relevant policy denies attaching the relationship, for example:Example target scenario:Parent resource: `projects`Parent ID: `1`Related association: `users`Related user ID to attach: `42`Expected policy: low-privileged users must not be able to attach users to projects.The UI/form request may be blocked:But the direct write endpoint can still be invoked:Run the attached PoC:If `GET /new` is forbidden or redirected but the direct POST succeeds, the authorization bypass is confirmed.To perform the actual attach:Expected vulnerable result:The low-privileged user can attach the related record despite `attach_<association>?` being denied.The parent record now includes the related record.ImpactThis vulnerability allows unauthorized relationship manipulation through Avo.Depending on the affected association, the impact can include:Privilege escalation by attaching a user to an admin group, privileged project, tenant, organization, role, or membership record.Cross-tenant data exposure when tenant/user/project membership determines record visibility.Integrity loss by changing ownership, assignment, access-control relationships, or business workflow state.Policy bypass even when Avo UI controls correctly hide the attach button or deny the attach form.Recommended FixEnforce attach authorization on the mutating endpoint.At minimum:Additionally:Authorize against the parent record and the selected related record before writing the relationship.Ensure `create` fails closed when `attach_<association>?` is missing and `explicit_authorization` is enabled.Add regression tests that directly POST to `/resources/:resource_name/:id/:related_name` while `attach_<association>?` returns `false`.Verify `has_many`, `has_one`, `has_many :through`, and `has_and_belongs_to_many` association paths all enforce the same server-side authorization.
CVSS v3.1: 9.6