-
MyFSIO v0.5.8 Beta Pre-Release
released this
2026-08-12 06:24:11 +00:00 | 0 commits to main since this releaseSecurity
Authorization & Authentication
- Fixed P0 bucket-name path escape: full S3 bucket-name syntax plus canonical containment is now enforced inside the storage backend (
require_bucket,bucket_exists,create_bucket, multipart paths, versioning checks) — a percent-encoded absolute path in the bucket position can no longer replaceSTORAGE_ROOT. - Fixed P0 query-selector precedence mismatch at both bucket and object level: one shared
BucketSubresource/ObjectSubresourceparser is used by the auth middleware and every dispatcher. Multiple selectors are rejected withInvalidArgumentat authorization time; non-dispatchable selectors returnMethodNotAllowedinstead of falling through. Closes an authenticated list-to-policy escalation, its unauthenticated variant on public-read buckets, and read-only principals writing/deleting via?attributes/?select/?uploads/?retention. - The auth middleware percent-decodes bucket, key, and copy-source so it authorizes the same strings the handlers act on.
- Every key in
DeleteObjectsis re-authorized individually — a prefix-scoped principal can no longer delete outside its prefix. - Presigned requests must sign every
x-amz-*header (exceptcontent-sha256/date/decoded-content-length), closing copy-source, ACL, SSE, and governance-bypass header injection by URL bearers. - Bucket policies fail closed on unsupported
Condition/NotPrincipal/NotAction/NotResourceelements at evaluation, and reject them at both write paths. is_adminnow requires an unrestricted policy prefix — a prefix-scoped wildcard policy no longer short-circuits every authorization check.- Bucket-policy
Resourcekeys match case-sensitively; bucket andActionmatching stay case-insensitive. - An unreadable
.bucket.jsonis treated as fail-closed across policy evaluation, object write/delete, and all config writes (previously acted as an empty config). x-amz-bypass-governance-retentionis honored only for admins or principals granted the newbypass_governanceIAM action (ors3:BypassGovernanceRetentionin a bucket policy), evaluated per key on bulk delete.- New IAM actions:
system:gc_read/gc_run/integrity_read/integrity_runreplace admin-only gating of GC and integrity on both the admin API and UI;ownershipControls/publicAccessBlockgain dedicatedownership_controls/public_access_blockactions;action_matchesgeneralized from hardcodediam:*to anynamespace:*. - Added missing bucket authorization to 11 UI handlers.
Path Traversal & Input Validation
- Multipart
uploadId/segment ids are validated as 32-hex before any filesystem join —abort_multipartpreviouslyremove_dir_all'd caller-controlled paths, capable of destroying.myfsio.sys/configin one request. - Reserved
__/x-amz-metadata keys are rejected at all five ingress points, including CopyObject, UI multipart init, and peer pull (x-amz-meta-__segments__could reach recursive segment deletion and redirect segment reads). - UI restore
version_idis validated to a single path component. PutBucketLoggingTargetBucketand website-domain mappings reject invalid bucket names;ListBucketsand--rebuild-listingskip invalid-named directories with a warning instead of failing.
Secrets & Encryption
- First-run and reset admin credentials are written encrypted, with a one-time plaintext-to-encrypted migration at startup; env-provided secrets are no longer echoed to stdout.
SECRET_KEYauto-generation persists to.myfsio.sys/config/.secret; the literal valuedev-secret-keyis rejected from both env and file.iam.json, KMS master keys,kms_keys.json,.connections_key,connections.json, and.secretare all written owner-only through shared atomic helpers (myfsio_common::fs_util).- The server exits non-zero when
ENCRYPTION_ENABLED/KMS_ENABLEDinit fails, and fails closed on bucket-default encryption instead of silently storing plaintext. - IAM disable-user/create-key/delete-key are routed through
load_config/save_configso revocation works against an encryptediam.json. - IAM mutations are serialized behind a mutation lock and persisted atomically (tmp + fsync + rename).
Web UI
- Fixed XSS via data-carrying inline
onclickhandlers — replaced with delegateddata-*listeners (verified in-browser). - Anonymous requests use ephemeral sessions that never enter the session store; capacity eviction prefers unauthenticated sessions.
GET/POST /loginis rate limited per IP (RATE_LIMIT_UI_LOGIN, default 20/minute) with a styled 429 page andRetry-After.
S3 API
- Object lock:
PutBucketObjectLockConfigurationvalidates the XML and requires versioning (409InvalidBucketState);DefaultRetentionis now actually applied at every user-facing object-creation path (explicit headers win; replication/peer-pull/restore untouched). Retention and legal-hold updates are check-and-set under the per-object stripe lock via newupdate_object_retention/update_object_legal_holdtrait methods — concurrent requests can no longer shorten COMPLIANCE retention, and legal-hold writes no longer clobber concurrent metadata. Same-mode extension needs no bypass; shortening, removal, and mode changes keep the bypass rules. - Static website hosting streams through the new
handlers/object_readdata plane: SSE-S3/SSE-KMS assets that were served as ciphertext are decrypted, HEAD reports plaintextContent-Length, 206 ranges use plaintext offsets, SSE-C assets return 403, and no path buffers whole objects in memory. - Ranged S3 GETs validate SSE-C keys like the whole-object path (400/403 instead of 500).
- Unknown
encoding-typevalues are rejected;max-keysis capped at 1000. - Date-based lifecycle rules are a no-op until the date passes, instead of using the configured date as an age cutoff.
- Request-body limits on every config/XML/JSON ingress (1 MiB config XML and Select, 8 MiB CompleteMultipartUpload/DeleteObjects, 1–2 MiB JSON, bounded relay-outbound, 1 MiB non-file multipart form fields) with a new
MaxMessageLengthExceedederror code.
Storage & Durability
- A failed PUT commit rolls back the archived version and metadata sidecar; the archived-null purge runs after the rename, so a failed commit can never destroy the prior null version.
- Fixed quarantine GC protection reading the wrong metadata root, multipart corruption false positives in the integrity scanner, and issue-count reporting; removed the legacy heal path.
- GC skips a bucket's segment sweep whenever the reference scan hit a read error, and reports the skip — an incomplete scan can no longer delete live segment data.
Background Services & Reliability
- Site sync aborts the cycle on any remote-listing failure instead of treating
NoSuchBucket/404 as an empty bucket (sync_deletionscould previously erase every locally synchronized object), and recordslast_error/last_error_atper bucket, surfaced on the Sites page. - The process exits non-zero when either listener task dies, so systemd restarts it.
Web UI
- UI part upload streams to disk with a 5 GiB cap instead of buffering each part twice in memory.
- Failed uploads surface the real S3 error reason in the toast and upload dialog instead of a bare failure count.
- Fixed dead cluster-page JavaScript, copy/move destination bucket default, audio preview stage height, and assorted polish.
- Each System dashboard card names the specific missing permission when access is denied.
Installer
install.sh/uninstall.shcanonicalize and refuse system paths, guard foreign data directories behind--adopt-data-dir, track installer-created users in a manifest so uninstall preserves pre-existing accounts, and re-installs preservemyfsio.env(--overwrite-envbacks up then regenerates).
Added
handlers/object_read.rs(shared streaming object-read data plane),myfsio_common::fs_util(atomic owner-only file helpers),login_rate_limited.html.- IAM actions:
bypass_governance,system:gc_read/gc_run/integrity_read/integrity_run,ownership_controls,public_access_block. - Error codes:
S3ErrorCode::MaxMessageLengthExceeded,S3ErrorCode::InvalidBucketState,StorageError::InvalidArgument. - Config:
RATE_LIMIT_UI_LOGIN(default20 per minute). - Validation helpers:
is_valid_multipart_id,is_reserved_metadata_key,is_reserved_user_metadata_key,is_safe_path_segment,bucket_name_rejection;BucketConfig::unreadable.
Removed
- Dead
has_query_keyhelper and the legacy integrity heal path.
Downloads
- Fixed P0 bucket-name path escape: full S3 bucket-name syntax plus canonical containment is now enforced inside the storage backend (