Skip to content

Releases

MiFlasher v2.0.4

Choose a tag to compare

@github-actions github-actions released this 05 Nov 01:47
948ff4b

Follow-up hardening release. Reported by Niranj R Mahaswar (@NiranjMahaswar).

Security

  • Backup restore could write outside its extraction directory on older Python versions. BackupManager._safe_extract() fell back to an unfiltered extractall() on Python 3.10.0-3.10.11 and 3.11.0-3.11.3, so a symlink inside a backup .tar.gz could be used to write files outside the extraction directory. Archive validation now lives in the new core/archive.py and no longer depends on the interpreter: every member is checked for absolute paths, path traversal, special files (devices, FIFOs), and symlink or hardlink targets that resolve outside the destination. The tarfile data filter is applied on top of this when the interpreter provides it
  • FlashManager._extract_tgz() uses the same validation. Previously it passed filter="data" unconditionally, which raised TypeError on the affected Python versions, and it only checked member names, not link targets

Fixed

  • Encrypted ZIPs and ZIPs using an unsupported compression method (RuntimeError, NotImplementedError), as well as truncated archives (EOFError, zlib.error), no longer kill the flash thread. They are logged as errors and the flash is aborted
  • Backup restore now reports corrupt or unsafe archives (TarError, EOFError, zlib.error, OSError) as errors instead of raising

Changed

  • Bumped version strings to 2.0.4

MiFlasher v2.0.3

Choose a tag to compare

@github-actions github-actions released this 04 Nov 19:54
ef2cb18

Security hardening release following the review of 2.0.2. Reported by
Niranj R Mahaswar (@NiranjMahaswar).

Security

  • Archive extraction can no longer escape its temp directory. A ROM named ...tar.gz resolved its extraction directory to TEMP_DIR/.., and the cleanup step then deleted ~/storage/downloads/MiFlasher including backups. Every extraction now uses a unique directory created with tempfile.mkdtemp() inside TEMP_DIR, so the archive file name no longer influences the path
  • FlashManager._cleanup() now refuses to remove anything that does not resolve strictly inside TEMP_DIR
  • /api/reboot now requires "confirm": true like the other state-changing endpoints, and the dashboard asks for confirmation before rebooting

Fixed

  • Corrupt ZIP/TAR archives and unsafe TAR links (BadZipFile, TarError, AbsoluteLinkError, OSError) no longer raise out of the flash path and kill the request thread; they are logged as errors and the flash is aborted. A partially extracted directory is removed when extraction fails
  • gui_port was saved from the GUI as a string and prevented the next miflasher gui start. ConfigManager.set() now converts integer settings to int, rejects non-numeric values and ports outside 1-65535, and /api/save-config reports invalid values. run_gui() also coerces an already-saved string port back to an integer
  • ConfigManager.set() no longer converts string settings such as theme or slot to booleans
  • Payload flashing uses a unique extraction directory instead of the shared payload_out

Documentation

  • SECURITY.md documents that a TLS reverse proxy must rewrite Host and Origin to the address the GUI is bound to, and that --host 0.0.0.0 disables Host header validation (the token and Origin checks still apply)
  • SECURITY.md credits the reporter

Changed

  • Bumped version strings to 2.0.3

MiFlasher v2.0.2

Choose a tag to compare

@github-actions github-actions released this 04 Nov 18:52
88405aa

Security release: fixes an unauthenticated remote code execution and arbitrary
device flashing issue in the Web GUI (CWE-306, CWE-352, CWE-94). Reported by
Niranj R Mahaswar (@NiranjMahaswar).
All users of 2.0.1 and earlier 2.x releases should upgrade.

Security

  • Web GUI now requires an access token. A random token is generated at every miflasher gui start and printed in the URL fragment (http://host:port/#token=...). Every /api/* request, GET and POST, must carry it in the X-MiFlasher-Token header and is compared in constant time. Requests without a valid token get 401
  • CSRF and cross-origin access closed. The token travels in a custom header, so a browser cannot send it cross-origin without a CORS preflight, and the server never answers preflights. Origin must match Host, and POST bodies must be Content-Type: application/json (text/plain is rejected with 415)
  • DNS rebinding protection. When bound to a loopback address the Host header must be localhost, 127.0.0.1, [::1] or the configured host with the active port
  • Destructive GUI actions no longer auto-confirm. CapturingLogger.confirm() used to always return True. /api/flash, /api/restore, /api/unlock and /api/wipe now require "confirm": true in the request body, sent only after the dashboard shows a confirmation dialog. Unlock and wipe no longer pass force=True and go through the normal confirmation path
  • ROM flash scripts are no longer executed blindly. flash_all.sh / flash_all_lock.sh / flash_all_except_data_storage.sh from a ROM archive now run only if one of these holds: --trust-script (CLI) or the "I trust this ROM" checkbox (GUI) is set, a --checksum was supplied and verified, or the user approves after the script content is printed for review (CLI, interactive). In non-interactive contexts such as the GUI the script is refused otherwise. The script path is also checked to resolve inside the extraction directory
  • Strict request validation in the GUI API. Flash target, slot and opts are allow-listed; local sources must be an existing .zip, .tgz, .gz, .img or .bin file; checksums must be hexadecimal; reboot mode is allow-listed; partition names must match [A-Za-z0-9_-]{1,64}; request bodies are capped at 1 MiB and must be JSON objects
  • Partition names are also validated inside BackupManager.backup() so a name like ../../x can no longer escape the backup directory from the CLI either
  • /api/save-config only accepts known configuration keys and can no longer change gui_host (network exposure can only be enabled from the command line or the config file)
  • Added Content-Security-Policy, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer, Cross-Origin-Resource-Policy: same-origin and Cache-Control: no-store to GUI responses
  • miflasher gui --host 0.0.0.0 (or any non-loopback host) now prints an explicit warning that anyone on the network holding the token can flash, wipe and unlock the connected device, and that traffic is plain HTTP

Added

  • --trust-script flag for miflasher flash to skip the script review prompt for ROMs you trust
  • Web GUI: SHA-256 checksum field and "I trust this ROM and allow its flash script to run" checkbox on the Flash page; confirmation dialogs for flash and restore, in addition to the existing ones for unlock and wipe
  • Logger.interactive attribute so core code can tell a terminal session from the GUI

Changed

  • Opening the dashboard now requires the full URL printed by miflasher gui, including the #token= fragment. The token is moved into sessionStorage and removed from the address bar on load
  • Bumped version strings to 2.0.2

Verified

  • Original proof of concept (POST /api/flash with Origin: https://evil.example and Content-Type: text/plain, no token): 403 Forbidden, no script executed
  • Same request without an Origin header: 401 Unauthorized
  • Valid token with Origin: https://evil.example: 403; valid token with text/plain: 415; forged Host: evil.example:18080: 403; wipe without confirm: 400; OPTIONS preflight: 501
  • A ROM archive containing a malicious flash_all.sh was refused with a valid token and confirm: true but no trust_script; $HOME/RCE_PROOF was not created. Interactive CLI run without --trust-script printed the script for review and aborted on a non-affirmative answer

MiFlasher v2.0.1

Choose a tag to compare

@github-actions github-actions released this 04 Aug 02:36
e2bd2e3

Patch release: fixes crashes, dead code, security holes, and non-functional
placeholders found in a full audit of v2.0.0.

Fixed

  • core/utils.py and core/payload.py were broken (ImportError: cannot import name 'log' from 'core.logger') and are now removed — they were already unused dead code, and CHANGELOG.md had incorrectly claimed they were removed in 2.0.0
  • miflasher wipe crashed with an unhandled traceback when adb/fastboot were not on PATH — now fails gracefully with a clear error message, consistent with every other command
  • core/downloader.py crashed at import time if the requests package was missing — now guarded, with a clear install hint shown only when a download is actually attempted
  • _flash_payload() told users to pip install payload-dumper-go, which doesn't exist as a pip package (it's a Go binary) — corrected to the real install instructions
  • Dead line of code in flash.py (self.log.progress.__doc__) removed
  • install.sh no longer installs the unused miunlock pip package, and no longer patches PATH with a directory (~/.local/bin) that the launcher isn't actually installed into

Security

  • Fixed a zip-slip / path-traversal vulnerability in ROM extraction (flash.py) — a malicious ROM archive with ../../ paths in its entries could previously write files outside the extraction directory. Archive members are now validated before extraction.
  • Fixed the same path-traversal issue in backup.py's restore() when extracting .tar.gz backups
  • Escaped device properties and log messages in the Web GUI dashboard before inserting them into innerHTML, closing a reflected-XSS path via crafted device getprop values

Added

  • --checksum flag for miflasher flash so --skip-verify has something real to skip; checksum is verified for both local files and downloaded ROMs when provided
  • --wipe-data on miflasher flash now actually erases userdata after a successful flash (previously accepted but silently ignored)
  • --method on miflasher flash rom (script / fastboot / adb) is now respected instead of being ignored
  • miflasher config values (slot, verbose, gui_host, gui_port) are now actually used as defaults by the CLI when the matching flag isn't passed explicitly — previously config --set had no effect on program behavior
  • Web GUI: /api/flash, /api/backup, /api/restore, /api/unlock, and /api/wipe now call the real core.* managers instead of returning canned placeholder messages; /api/save-config actually persists settings; /api/config returns the real saved config instead of hardcoded defaults; wiping dalvik-cache from the GUI now runs the adb rm -rf command instead of being silently skipped
  • colorama.init() is now called so the colorama dependency in requirements.txt is actually used (fixes broken ANSI colors on older Windows terminals)
  • GUI server switched from single-threaded HTTPServer to ThreadingHTTPServer so device polling keeps working while a flash/backup/restore is in progress

MiFlasher v2.0.0

Choose a tag to compare

@djunekz djunekz released this 20 Feb 09:38
dffe7ec

What's New

  • flash target vbmeta, recovery, super
  • progress bar rich, eta, size
  • download resumable, retry, checksum
  • gui interface
  • logging
  • error handling

Added

  • reboot mode (system, bootloader, recovery, fastboot)
  • backup (all partitions + compress)
  • full restore from backup
  • wipe (chache, data, dalvik)

Update

  • cli and gui interface
  • device stats info
  • unlock verified with adb and official tool

MiFlasher v1.0.0

Choose a tag to compare

@djunekz djunekz released this 20 Feb 06:37
4844347

Release MiFlasher v1.0.0

Beta Release