CVE-2026-55518
Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation
Avo is a framework to create admin panels for Ruby on Rails apps. Prior to 3.32.1 and 4.0.0.beta.51, Avo's association attach workflow checks attach_<association>? in the UI and GET /resources/:resource/:id/:related/new path, but the actual write endpoint, POST /resources/:resource/:id/:related, does not run the same authorization check before mutating the association through Avo::AssociationsController#create. An authenticated low-privileged Avo user can bypass hidden or disabled attach controls and directly attach related records to a parent record by sending a crafted POST request, which can lead to privilege escalation and cross-tenant data exposure where associations represent authorization-bearing relationships. This issue is fixed in versions 3.32.1 and 4.0.0.beta.51.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
9.6
Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation
Avo is a framework to create admin panels for Ruby on Rails apps. Prior to 3.32.1 and 4.0.0.beta.51, Avo's association attach workflow checks attach_<association>? in the UI and GET /resources/:resource/:id/:related/new path, but the actual write endpoint, POST /resources/:resource/:id/:related, does not run the same authorization check before mutating the association through Avo::AssociationsController#create. An authenticated low-privileged Avo user can bypass hidden or disabled attach controls and directly attach related records to a parent record by sending a crafted POST request, which can lead to privilege escalation and cross-tenant data exposure where associations represent authorization-bearing relationships. This issue is fixed in versions 3.32.1 and 4.0.0.beta.51.
- Record
CVE-2026-55518- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-639, CWE-862, CWE-863
- Updated
- 2026-11-02
EUVDEUVD-2026-45334
9.6
Avo is a framework to create admin panels for Ruby on Rails apps. Prior to 3.32.1 and 4.0.0.beta.51, Avo's association attach workflow checks attach_<association>? in the UI and GET /resources/:resource/:id/:related/new path, but the actual write endpoint, POST /resources/:resource/:id/:related, does not run the same authorization check before mutating the association through Avo::AssociationsController#create. An authenticated low-privileged Avo user can bypass hidden or disabled attach controls and directly attach related records to a parent record by sending a crafted POST request, which can lead to privilege escalation and cross-tenant data exposure where associations represent authorization-bearing relationships. This issue is fixed in versions 3.32.1 and 4.0.0.beta.51.
- Record
EUVD-2026-45334- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-8fq9-273g-6mrg
9.6
Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation
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:
# 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:
# 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:
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:
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:
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:
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:
# 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:
- 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:
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:
GET /admin/resources/projects/1/users/new
But the direct write endpoint can still be invoked:
POST /admin/resources/projects/1/users
Content-Type: application/x-www-form-urlencoded
…
- Record
GHSA-8fq9-273g-6mrg- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-639, CWE-862, CWE-863
- Updated
- 2026-11-02
NVD
9.6
Avo is a framework to create admin panels for Ruby on Rails apps. Prior to 3.32.1 and 4.0.0.beta.51, Avo's association attach workflow checks attach_<association>? in the UI and GET /resources/:resource/:id/:related/new path, but the actual write endpoint, POST /resources/:resource/:id/:related, does not run the same authorization check before mutating the association through Avo::AssociationsController#create. An authenticated low-privileged Avo user can bypass hidden or disabled attach controls and directly attach related records to a parent record by sending a crafted POST request, which can lead to privilege escalation and cross-tenant data exposure where associations represent authorization-bearing relationships. This issue is fixed in versions 3.32.1 and 4.0.0.beta.51.
- Record
CVE-2026-55518- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-639, CWE-862, CWE-863
- Updated
- 2026-11-02
OSV
9.6
Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation
Avo is a framework to create admin panels for Ruby on Rails apps. Prior to 3.32.1 and 4.0.0.beta.51, Avo's association attach workflow checks attach_<association>? in the UI and GET /resources/:resource/:id/:related/new path, but the actual write endpoint, POST /resources/:resource/:id/:related, does not run the same authorization check before mutating the association through Avo::AssociationsController#create. An authenticated low-privileged Avo user can bypass hidden or disabled attach controls and directly attach related records to a parent record by sending a crafted POST request, which can lead to privilege escalation and cross-tenant data exposure where associations represent authorization-bearing relationships. This issue is fixed in versions 3.32.1 and 4.0.0.beta.51.
- Record
CVE-2026-55518- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-639, CWE-862, CWE-863
- Updated
- 2026-11-02
OSVGHSA-8fq9-273g-6mrg
9.6
Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation
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:
# 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:
# 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:
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:
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:
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:
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:
# 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:
- 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:
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:
GET /admin/resources/projects/1/users/new
But the direct write endpoint can still be invoked:
POST /admin/resources/projects/1/users
Content-Type: application/x-www-form-urlencoded
…
- Record
GHSA-8fq9-273g-6mrg- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N - Weakness
- CWE-639, CWE-862, CWE-863
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
avoRubyGems |
through 3.32.0 | 3.32.1 |
avoRubyGems |
4.0.0.beta.1 up to 4.0.0.beta.51 | 4.0.0.beta.51 |
avoRubyGems |
before 3.32.1, plus listed versions 0.2.00.2.10.2.20.2.30.2.4 Show 45 moreShow less0.2.50.3.10.3.20.4.10.4.100.4.20.4.30.4.40.4.50.4.60.4.70.4.80.4.90.5.0.beta10.5.0.beta100.5.0.beta110.5.0.beta120.5.0.beta130.5.0.beta140.5.0.beta150.5.0.beta20.5.0.beta30.5.0.beta40.5.0.beta50.5.0.beta60.5.0.beta70.5.0.beta80.5.0.beta91.0.01.0.11.0.21.0.41.0.51.1.01.1.0.pre.11.10.01.10.11.10.21.10.31.11.01.11.11.11.21.11.31.11.41.11.5 |
3.32.1 |
avoRubyGems |
4.0.0.beta.1 up to 4.0.0.beta.51, plus listed versions 4.0.0.beta.104.0.0.beta.114.0.0.beta.124.0.0.beta.134.0.0.beta.14 Show 44 moreShow less4.0.0.beta.154.0.0.beta.164.0.0.beta.174.0.0.beta.184.0.0.beta.194.0.0.beta.24.0.0.beta.204.0.0.beta.214.0.0.beta.224.0.0.beta.234.0.0.beta.244.0.0.beta.254.0.0.beta.264.0.0.beta.274.0.0.beta.284.0.0.beta.294.0.0.beta.34.0.0.beta.304.0.0.beta.314.0.0.beta.324.0.0.beta.334.0.0.beta.344.0.0.beta.354.0.0.beta.364.0.0.beta.374.0.0.beta.384.0.0.beta.394.0.0.beta.44.0.0.beta.404.0.0.beta.414.0.0.beta.424.0.0.beta.434.0.0.beta.444.0.0.beta.454.0.0.beta.464.0.0.beta.474.0.0.beta.484.0.0.beta.494.0.0.beta.54.0.0.beta.504.0.0.beta.64.0.0.beta.74.0.0.beta.84.0.0.beta.9 |
4.0.0.beta.51 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-55518 is a critical vulnerability (CVSS 9.6) in Avo-hq Avo, published June 17, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.41%, the 35th percentile. Fixed in avo 3.32.1.
References
github.com/avo-hq/avo/security/advisories/GHSA-8fq9-273g-6mrg
github.com/avo-hq/avo/pull/4568
github.com/avo-hq/avo/commit/995928e586fd1788dd496bd51c4dbe4a79cb2b9c
github.com/avo-hq/avo/releases/tag/v3.32.1
nvd.nist.gov/vuln/detail/CVE-2026-55518
github.com/rubysec/ruby-advisory-db/blob/master/gems/avo/CVE-2026-55518.yml
Left out here: 521 versions and the rest of 2 source descriptions. The JSON record has them.