GHSA-PFCQ-4GJR-6GJM
Vulnerability from github – Published: 2026-04-22 19:24 – Updated: 2026-04-22 19:24Missing Admin Auth on Notification Target Endpoints in RustFS
Finding Summary
All four notification target admin API endpoints in rustfs/src/admin/handlers/event.rs use a check_permissions helper that validates authentication only (access key + session token), without performing any admin-action authorization via validate_admin_request. Every other admin handler in the codebase correctly calls validate_admin_request with a specific AdminAction. This is the only admin handler file that skips authorization.
A non-admin user can overwrite a shared admin-defined notification target by name, causing subsequent bucket events to be delivered to an attacker-controlled endpoint. This enables cross-user event interception and audit evasion.
What Was Proven Live
- Authorization bypass on all four endpoints (03_readonly_user_bypass.py)
- PUT, GET list, GET arns, DELETE all return 200 for readonly-user
- Control routes (list-users, kms/status) correctly return 403
-
Unauthenticated requests correctly rejected (403 Signature required)
-
SSRF via health probe (04_ssrf_listener_landing.py)
- HEAD request from rustfs container to attacker-controlled listener
-
No host validation: only scheme check (http/https)
-
Target hijacking and event exfiltration (05_target_hijacking.py, 06_full_event_exfil.py)
- Readonly-user overwrites admin-configured target URL by name
- Subsequent S3 events delivered to attacker-controlled endpoint
-
Captured event body includes object keys, bucket names, user identities, and request metadata
-
Audit evasion (05_target_hijacking.py)
- Readonly-user can delete unbound targets
- Readonly-user can overwrite bound targets (silently redirecting events)
Escalation Vectors Tested But Not Viable
- Self-referencing webhook to admin API (13_self_referencing_test.py)
- Webhook sends unsigned POST with event JSON body
- Admin endpoints require SigV4 auth -- unsigned request rejected
-
"Confused deputy" via self-referencing does NOT work
-
Protocol smuggling via non-HTTP targets
- Only 2 target types implemented: webhook and MQTT (
event.rs:613enforces this) - No Redis, Kafka, AMQP, or other protocol targets exist
- CRLF injection in webhook config fields sanitized by reqwest
-
MQTT uses rumqttc (pure Rust binary protocol client), no raw TCP injection
-
MQTT target for RCE
- No unsafe code in MQTT handler
- rumqttc 0.29.0 has no known public CVEs
-
No Command::new, template engines, or deserialization of broker responses
-
Unauth access
- Endpoints correctly reject unauthenticated requests (403)
- Endpoints correctly reject invalid credentials (403)
Prior Art
No existing advisory covers notification target endpoints. 11 published GHSAs on rustfs/rustfs cover different handlers. Closest: - CVE-2026-22042 (ImportIam wrong action constant) -- same bug class, different file - CVE-2026-22043 (deny_only short-circuit) -- different bug class
Recommendation
Submit via GitHub PVR. The finding is well-supported with live PoC, code references, and clear root cause. The fix is straightforward (add validate_admin_request calls to event.rs handlers). Core submission should reference 2-3 focused PoC scripts (readonly bypass, target hijack, event exfil), not the full set of 13 exploratory scripts.
Koda Reef
Patch
This issue has been patched in version https://github.com/rustfs/rustfs/releases/tag/1.0.0-alpha.94.
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "rustfs"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "0.0.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-40937"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-22T19:24:53Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "# Missing Admin Auth on Notification Target Endpoints in RustFS\n\n\n### Finding Summary\n\nAll four notification target admin API endpoints in `rustfs/src/admin/handlers/event.rs` use a `check_permissions` helper that validates authentication only (access key + session token), without performing any admin-action authorization via `validate_admin_request`. Every other admin handler in the codebase correctly calls `validate_admin_request` with a specific `AdminAction`. This is the only admin handler file that skips authorization.\n\nA non-admin user can overwrite a shared admin-defined notification target by name, causing subsequent bucket events to be delivered to an attacker-controlled endpoint. This enables cross-user event interception and audit evasion.\n\n### What Was Proven Live\n\n1. **Authorization bypass on all four endpoints** (03_readonly_user_bypass.py)\n - PUT, GET list, GET arns, DELETE all return 200 for readonly-user\n - Control routes (list-users, kms/status) correctly return 403\n - Unauthenticated requests correctly rejected (403 Signature required)\n\n2. **SSRF via health probe** (04_ssrf_listener_landing.py)\n - HEAD request from rustfs container to attacker-controlled listener\n - No host validation: only scheme check (http/https)\n\n3. **Target hijacking and event exfiltration** (05_target_hijacking.py, 06_full_event_exfil.py)\n - Readonly-user overwrites admin-configured target URL by name\n - Subsequent S3 events delivered to attacker-controlled endpoint\n - Captured event body includes object keys, bucket names, user identities, and request metadata\n\n4. **Audit evasion** (05_target_hijacking.py)\n - Readonly-user can delete unbound targets\n - Readonly-user can overwrite bound targets (silently redirecting events)\n\n### Escalation Vectors Tested But Not Viable\n\n1. **Self-referencing webhook to admin API** (13_self_referencing_test.py)\n - Webhook sends unsigned POST with event JSON body\n - Admin endpoints require SigV4 auth -- unsigned request rejected\n - \"Confused deputy\" via self-referencing does NOT work\n\n2. **Protocol smuggling via non-HTTP targets**\n - Only 2 target types implemented: webhook and MQTT (`event.rs:613` enforces this)\n - No Redis, Kafka, AMQP, or other protocol targets exist\n - CRLF injection in webhook config fields sanitized by reqwest\n - MQTT uses rumqttc (pure Rust binary protocol client), no raw TCP injection\n\n3. **MQTT target for RCE**\n - No unsafe code in MQTT handler\n - rumqttc 0.29.0 has no known public CVEs\n - No Command::new, template engines, or deserialization of broker responses\n\n4. **Unauth access**\n - Endpoints correctly reject unauthenticated requests (403)\n - Endpoints correctly reject invalid credentials (403)\n\n### Prior Art\n\nNo existing advisory covers notification target endpoints. 11 published GHSAs on rustfs/rustfs cover different handlers. Closest:\n- CVE-2026-22042 (ImportIam wrong action constant) -- same bug class, different file\n- CVE-2026-22043 (deny_only short-circuit) -- different bug class\n\n### Recommendation\n\nSubmit via GitHub PVR. The finding is well-supported with live PoC, code references, and clear root cause. The fix is straightforward (add `validate_admin_request` calls to event.rs handlers). Core submission should reference 2-3 focused PoC scripts (readonly bypass, target hijack, event exfil), not the full set of 13 exploratory scripts.\n\n\nKoda Reef\n\n### Patch\nThis issue has been patched in version https://github.com/rustfs/rustfs/releases/tag/1.0.0-alpha.94.",
"id": "GHSA-pfcq-4gjr-6gjm",
"modified": "2026-04-22T19:24:53Z",
"published": "2026-04-22T19:24:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/rustfs/rustfs/security/advisories/GHSA-pfcq-4gjr-6gjm"
},
{
"type": "PACKAGE",
"url": "https://github.com/rustfs/rustfs"
},
{
"type": "WEB",
"url": "https://github.com/rustfs/rustfs/releases/tag/1.0.0-alpha.94"
}
],
"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"
}
],
"summary": "RustFS: Missing admin authorization on notification target endpoints allows unauthenticated configuration of event webhooks"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.