mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
d874831cec
* fix(kms): do not include secret value in static KMS format error The malformed-format error message in build_static_kms_config embedded the raw env var value. The most likely misconfiguration is setting RUSTFS_KMS_STATIC_SECRET_KEY to the bare base64 key without the <key-name>: prefix, in which case the full secret key material would be written to startup logs. Drop the value from the message, matching the equivalent parsing error in KmsConfig::from_env(). * chore(security): add guardrails against secret values in error strings Follow-up to the PR #5222 review finding fixed in PR #5243: a config value that fails secret-format parsing is typically the raw secret itself, and error messages are log content — they propagate via ? and are printed by startup/error logging far from the construction site. Three layers so this class of leak is caught earlier next time: - security-advisory-lessons: state explicitly that error/panic messages are log content; parse-failure hints must name the env var and expected format, never echo the input. Add a matching review prompt. - adversarial-validation: add a security-reviewer probe that greps error-construction sites on secret-bearing config paths for interpolation of the raw value, including the duplicated-parse trap where the leak hid. - check_logging_guardrails.sh: mechanical backstop — flag inline format interpolation of secret-named identifiers (secret/password/passwd/ private_key) in checked files; add crates/kms/src/config.rs (the twin parse site) to the checked list. Verified the check passes on the fixed tree and catches the original leak at rustfs/src/init.rs:399.
14 KiB
14 KiB
name, description
| name | description |
|---|---|
| security-advisory-lessons | Apply RustFS security lessons distilled from repository GitHub Security Advisories. Use when making or reviewing RustFS code changes, doing security checks, handling PR review for auth/authz, IAM, storage, RPC, logging, CORS, console/browser, encryption, policy, or endpoint changes, and when deciding which security regression tests are required. |
RustFS Security Advisory Lessons
Use this skill as a RustFS-specific security lens before changing or approving code. For the distilled advisory lessons and review patterns, read advisory-patterns.md.
When currentness matters, fetch the live advisory inventory instead of relying on this skill as a status mirror:
gh api repos/rustfs/rustfs/security-advisories --paginate \
--jq '.[] | {ghsa_id,state,severity,summary,updated_at}'
Fetch full advisory details only when the live summary suggests a new or changed lesson:
gh api repos/rustfs/rustfs/security-advisories/<GHSA_ID>
For the full pattern map, read advisory-patterns.md.
Workflow
1. Scope the change
- Identify touched routes, protocol frontends, handlers, storage paths, credentials, logs, browser surfaces, CI/release code, and policy checks.
- Treat these paths as security-sensitive by default:
rustfs/src/admin/,rustfs/src/storage/,rustfs/src/auth.rs,rustfs/src/server/layer.rs,crates/iam/,crates/policy/,crates/credentials/,crates/ecstore/src/rpc/,crates/protocols/,crates/rio/, OIDC/STS federation code, and console preview/auth code.
2. Map to advisory classes
- Read advisory-patterns.md for matching GHSA lessons.
- Do not rely on advisory titles alone. Confirm whether the issue is authentication, authorization, input validation, storage invariant, browser isolation, logging, or operational hardening.
3. Verify fail-closed behavior
- Check that unauthenticated, wrong-permission, cross-user, cross-bucket, malformed-input, and default-config cases fail explicitly.
- Prefer exact action/permission checks over broad helper calls or inferred ownership.
- Confirm lower storage/RPC layers do not bypass checks done in upper layers.
4. Require regression evidence
- For behavior changes, add focused negative tests that reproduce the advisory class.
- For sensitive fixes, include tests for the bypass form, not only the happy path.
- If a test is impractical, explain the residual risk and provide a manual verification command.
5. Report clearly
- Lead with concrete findings and file/line evidence.
- Separate proven vulnerabilities from hardening risks.
- Avoid exaggerating unauthenticated impact when the code actually rejects unauthenticated requests but allows a low-privileged authenticated bypass.
Advisory-Derived Guardrails
Auth and admin authorization
- Every admin or diagnostic route needs an explicit authn and authz story. Route registration, router whitelist, and handler-level authorization must agree.
- Match the admin action to the operation exactly. Copy-paste action constants are a known RustFS vulnerability class.
- Avoid authentication-only helpers for state-changing admin APIs; use
validate_admin_requestor the established equivalent with the rightAdminAction. - Read-only admin APIs such as metrics, server info, and diagnostics still require admin authorization; checking only that credentials exist is not enough.
- Replication admin reads can expose remote target credentials; list/get target endpoints require replication/admin authorization and must not return secrets to low-privilege callers.
- Do not assume admin-action
Resourcescoping constrains blast radius unless the policy engine actually enforces resources for that action.
IAM and service accounts
- Treat imported IAM payload fields as attacker-controlled:
parent,claims,accessKey,secretKey, status, policy names, and groups. - For service account create/update/import, prove parent ownership or root/admin authority before writing credentials or claims; an action permission alone must not allow choosing root or another user as
target_user. - Treat IAM export packages as credential disclosure surfaces; never include plaintext user or service-account secret keys unless the caller is allowed to recover those secrets and the export format is intentionally sealed.
- Do not let
deny_onlyor "no explicit deny" become an allow decision that skips required allow checks. - Test cross-user list/update/import flows with wrong, correct, self, parent, and root identities.
STS, OIDC, and federation flows
- Every STS endpoint must have an explicit authentication story: SigV4 where required, OIDC token verification for web identity, and role/session policy validation before issuing credentials.
- JWT session tokens must be signed and verified by a trusted issuer/key path, not by service-account-controlled material or a reused root secret.
- JWT verification must enforce required claims and expiration for every bearer token path; "allow missing exp" is never acceptable for user-presented credentials.
- Public OIDC bootstrap and callback routes must treat
Host,X-Forwarded-Proto, redirect targets,state, and callback parameters as untrusted; credential-bearing redirects require a configured, allowlisted origin. - OIDC discovery and validation URLs are SSRF sinks. Resolve and classify hostnames at connection time, reject rebinding to loopback/private/link-local ranges, and do not rely on literal string checks.
S3 copy, multipart, and presigned POST
- Multipart copy must enforce source
GetObjectand destinationPutObjectsemantics equivalent toCopyObject, including copy-source and policy conditions. - Do not let
CreateMultipartUpload,UploadPartCopy,CompleteMultipartUpload, orAbortMultipartUploadreturn success without authorization. - Presigned POST policies are server-side contracts. Enforce
content-length-range, key prefix, exact metadata/content-type, and all signed policy conditions.
Protocol frontends and IAM parity
- FTP/FTPS, SFTP, gateway, and other protocol drivers must enforce IAM per operation before calling storage backends; authentication to a protocol listener is not authorization.
- Match protocol commands to the same S3 actions as HTTP, such as
RETRtoGetObject,SIZE/MDTMtoHeadObject,MKDtoCreateBucket, and bucket probes toListBucketorHeadBucket. - Review every handler in a protocol driver, not only the changed handler, because RustFS advisories show mixed guarded and unguarded siblings in the same driver.
- Regression tests for protocol frontends should deny the shared authorization hook and prove the backend is not reached for the denied command.
- Compare protocol secrets in constant time, normalize invalid-user and invalid-secret failures where practical, and add rate limiting before exposing password-style protocol endpoints.
Paths, object keys, and filesystem access
- Never join untrusted bucket/object/RPC path strings onto filesystem roots without normalization and boundary checks.
- Reject or safely handle
.., absolute paths, URL-encoded traversal, platform separators, empty components, and paths that canonicalize outside the intended root. - Validate both S3 object-key paths and internode/RPC disk paths; storage helpers can bypass S3 authorization if they trust already-parsed paths.
- Archive auto-extract paths are object keys too. Validate tar/zip entry names before IAM checks and before storage writes, and prove cleaned paths cannot cross bucket or prefix boundaries.
Secrets, default credentials, and crypto
- Do not ship hard-coded shared tokens, HMAC secrets, private keys, or production test keys.
- Defaults for root credentials and internode/RPC auth must fail closed for network-reachable deployments or generate per-install random secrets; warnings alone are not a security boundary.
- Keep cryptographic roles separated: root S3 credentials, RPC HMAC keys, and STS/JWT signing keys must not be reused or deterministically derived from each other.
- License or token validation must use signatures with embedded public/verifying keys only; do not use private-key decryption as authenticity.
- Plan key rotation and key IDs when removing exposed keys.
Logging and debug output
- Logs must never include access keys beyond safe identifiers, secret keys, session tokens, JWT claims, HMAC secrets, expected signatures, license secrets, or raw response bodies containing credentials.
- Treat
Debugimplementations,?valuetracing, merged config dumps, and dependency-level HTTP body logging as leak surfaces. - Error and panic messages are log content: they propagate through
?and get printed byerror!/startup logging far from where they were constructed. Never interpolate a raw config or credential value into an error string. - A value that fails secret-format parsing is usually the secret itself (e.g. a bare base64 key missing its
<name>:prefix), so a parse-failure hint must name the env var or file and the expected format, never echo the input. RedactingDebugimpls does not cover this channel. - Add log-capture tests or targeted unit tests for redaction wrappers when changing credential structs or response bodies.
RPC, parsing, and panic safety
- Treat all RPC payload bytes as attacker-controlled. Replace
unwrap,expect, and panic-prone deserialization with typed errors. - Malformed request tests should cover empty bytes, truncated MessagePack/protobuf, invalid enum values, stale timestamps, and invalid signatures.
- RPC authentication must be independently strong; do not depend on S3 admin credentials unless the fallback is explicit and safe.
- RPC signatures must bind the exact generated gRPC method path, timestamp, and request method. Service-prefix signatures must not authorize a different concrete NodeService call.
Browser, CORS, and console surfaces
- Do not reflect arbitrary
Originwhile also allowing credentials. Default CORS should be no CORS unless explicitly configured. - Do not render user-controlled object content in a same-origin iframe with console credentials available to JavaScript.
- Prefer origin separation for object preview/download,
nosniff, CSP, strict content-type handling, and avoiding durable credentials inlocalStorage. - Preview safety must be based on trusted content type and sandboxing, not object names or extensions such as
.pdf. - Console license/version-like metadata endpoints should expose only coarse public data unless authenticated, especially subject names and expiration timestamps.
Profiling, debug, and health endpoints
- Profiling and debug endpoints are not health checks. They require admin auth, opt-in enablement, rate limiting, and safe responses.
- Do not return absolute filesystem paths or other deployment layout in unauthenticated or low-privilege responses.
- Ensure health endpoint allowlists cannot accidentally include expensive diagnostics.
Trusted proxy and network identity
- Only honor
X-Forwarded-FororX-Real-IPwhen the request came from a configured trusted proxy. - Apply the same trusted-proxy rule to scheme and host derivation; direct clients must not control security-sensitive redirects through
Host,X-Forwarded-Host, orX-Forwarded-Proto. - Direct clients must use the socket peer address for
aws:SourceIpand policy condition evaluation. - Add tests for direct spoofed headers and trusted-proxy headers.
SSE and storage invariants
- Encryption metadata is not proof that bytes were encrypted on disk.
- When touching reader/writer wrappers such as hashing, encryption, compression, or warp readers, verify wrapper order and inspect stored bytes in regression tests.
- Avoid helper shortcuts that unwrap nested readers and accidentally bypass encryption or integrity layers.
Review Prompts
Use these prompts while reviewing a diff:
- Could a low-privileged authenticated user reach this path with the wrong action, parent, bucket, or source object?
- Does a non-HTTP protocol path call the same authorization boundary as the S3 API before touching storage?
- Does a public/default/empty config change security behavior from fail-closed to fail-open?
- Is any attacker-controlled value later used as a path, policy condition, credential identity, log field, URL, Origin, or response body?
- Does this response contain stored replication, remote target, or service credentials that need redaction or stricter authorization?
- Does any error constructor or
format!interpolate a variable that can hold secret material, including a config parse error that echoes the raw input? - Does an IAM export/import path expose or trust plaintext credential secrets beyond the caller's intended authority?
- Can this STS/OIDC path issue credentials without SigV4, trusted issuer validation, allowlisted redirects, or trusted-proxy host/scheme handling?
- Can a service-account or STS token omit
exp, forgesessionPolicy, or use a principal-controlled key as signing authority? - Does this outbound validation path resolve attacker-supplied hostnames and reject private, loopback, link-local, and rebound addresses at the actual connection boundary?
- Is an archive entry, object key, or policy resource normalized differently between authorization and storage?
- Is the same operation implemented in multiple paths, such as
CopyObjectvsUploadPartCopy, and do all paths enforce the same security contract? - Does a preview or browser-surface fix preserve the original security invariant when adding alternate viewers or file-type detection?
- Does the test prove the exploit form is denied, or only that the intended form still works?