Avo CVE-2026-55518
CRITICALSeverity by source
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
Network-reachable Avo endpoint (AV:N), single crafted POST (AC:L), any authenticated Avo user suffices (PR:L), no UI; scope changes because Avo's auth boundary is bypassed to affect host-app tenancy (S:C), high C/I, no availability impact.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
Lifecycle Timeline
2DescriptionGitHub Advisory
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: :destroyThe 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
endcreate_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
endThe only attach-specific authorization helper is:
def authorize_attach_action
authorize_if_defined "attach_#{@field.id}?"
endBecause 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: :destroyThe 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
endHowever, 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
endExample 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/newBut the direct write endpoint can still be invoked:
POST /admin/resources/projects/1/users
Content-Type: application/x-www-form-urlencoded
authenticity_token=<CSRF>&fields[related_id]=42Run the attached PoC:
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-newIf GET /new is forbidden or redirected but the direct POST succeeds, the authorization bypass is confirmed.
To perform the actual attach:
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-attachExpected 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:
before_action :authorize_attach_action, only: [:new, :create]Additionally:
- Authorize against the parent record and the selected related record before writing the relationship.
- Ensure
createfails closed whenattach_<association>?is missing andexplicit_authorizationis enabled. - Add regression tests that directly POST to
/resources/:resource_name/:id/:related_namewhileattach_<association>?returnsfalse. - Verify
has_many,has_one,has_many :through, andhas_and_belongs_to_manyassociation paths all enforce the same server-side authorization.
Articles & Coverage 1
AnalysisAI
Authorization bypass in Avo (Ruby on Rails admin framework) versions <= 3.32.0 and 4.0.0.beta.1 through 4.0.0.beta.50 allows authenticated low-privileged users to attach arbitrary related records to parent resources via a direct POST to the associations endpoint, bypassing the attach_<association>? policy enforced only on the form-rendering GET. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Requires the target Rails application to mount the Avo engine with authorization enabled, an authenticated session for any Avo user (PR:L), and knowledge of the parent resource name, parent ID, related association name, and related record ID - all typically enumerable from the Avo UI or predictable integers. … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N vector (9.6) is consistent with the description: network-reachable Avo endpoint, low complexity (single crafted POST), low-privileged authenticated user, no UI, and scope-changed confidentiality/integrity impact because the bypass can cross tenancy/role boundaries in the host application. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | A low-privileged Avo user authenticates to the admin panel and observes that the UI hides the "Attach users" button on a Project, indicating `attach_users?` returns false for their role. Using the published Python PoC, they reuse their session cookie to send `POST /admin/resources/projects/1/users` with `fields[related_id]=<their own user id>` and a valid CSRF token, attaching themselves to a privileged project and gaining access to its tenant-scoped data on subsequent reads. |
| Remediation | Vendor-released patch: upgrade `avo` to 3.32.1 (3.x users) or 4.0.0.beta.51 (4.x beta users) as published in GHSA-8fq9-273g-6mrg (https://github.com/avo-hq/avo/security/advisories/GHSA-8fq9-273g-6mrg). … Detailed patch versions, workarounds, and compensating controls in full report. |
Recommended ActionAI
Within 24 hours: Inventory all Avo deployments by checking Gemfile.lock and deployed application versions to determine exposure scope; document business-criticality of each Avo instance. …
Sign in for detailed remediation steps and compensating controls.
Threat intelligence, references, and detailed analysis are available after sign-in.
More from same product – last 7 days
Authentication bypass in StarTree mcp-pinot versions 3.0.1 and earlier exposes the Model Context Protocol HTTP server on
Unauthenticated remote code execution in Crawl4AI versions <= 0.8.6 allows attackers to escape the AST-based sandbox in
InHand Networks IR912 V1.0.0.r20042 and IR915 V1.0.0.r20042 (including earlier versions) were discovered to contain a co
InHand Networks IR912 V1.0.0.r20042 and IR915 V1.0.0.r20042 (including earlier versions) were discovered to contain a co
Remote code execution in Langflow versions through 1.9.1 allows unauthenticated attackers to execute arbitrary Python co
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-8fq9-273g-6mrg