Security
Fixes for several issues found in a static-analysis security audit. None of these have a known in-the-wild exploit, but operators should still upgrade.
- Path traversal in user-data archive import (
POST /settings/users/import) — a malicious archive whose JSON manifest referenced files via..could attach arbitrary host files (e.g.config/master.key,/proc/self/environ) to the user's import record and download them. - OAuth web callback (Google / GitHub / OIDC) used to silently link an existing local-password account to an incoming OAuth identity on email match, with no
email_verifiedcheck or consent. The web flow now mirrors the mobile-API flow: the user must confirm the link. - SSRF blocklist for the
immich_url/photoprism_urlsettings missed RFC1918, CGNAT, IPv6 ULA, multicast and reserved ranges. Cloud installs now reject those; self-hosted gets a smaller blocklist that still catches non-http schemes, cloud-metadata IPs and multicast while permitting LAN / loopback / Docker DNS. - Web OTP challenge (
POST /users/otp_challenge) had no rate limit, leaving 2FA brute-forceable given a leaked password. Added rack-attack throttles (5/15min per session, 20/15min per IP) plus an in-controller cap of 5 invalid attempts. - Stored XSS via
family.namerendered throughnotification.content.html_safeis now passed throughsanitize. - Disabling 2FA now requires both the password AND a current authenticator code (or backup code), on web and API.
- Default
prometheus/prometheuscredentials for/metricsare gone — the endpoint refuses until bothMETRICS_USERNAMEandMETRICS_PASSWORDare set. - Devise minimum password length raised from 6 to 12.
- API keys generated by new accounts are 256-bit (was 128-bit). Existing keys keep working.
- OwnTracks point ingest replaces a blanket
params.permit!with the documented field whitelist.
Added
- Polarsteps support —
locations.jsonand segment-array exports now import directly. - Files with unsupported extensions are rejected in the browser before upload starts.
- Clear, actionable error messages when an unsupported file is uploaded — points to the right file in your Takeout instead of a generic "Unable to detect file format".
Changed
- Monthly and yearly email digests now hide countries and cities with 1 hour or less of time spent, so the Top Countries / Top Cities lists no longer get padded with
0hand1hentries. - Disabling 2FA via
/settings/two_factornow asks for both your password and a current authenticator code (or one of your backup codes). The web form has been updated; API clients must sendpasswordANDotp_codetoDELETE /api/v1/users/me/two_factor. - Setting a new password (signup, password change, password reset) now requires at least 12 characters. Existing shorter passwords still work for sign-in.
/metricsendpoint: if you scrape Prometheus metrics, setMETRICS_USERNAMEandMETRICS_PASSWORDin your environment. With them unset,/metricsnow returns 503.- OAuth (web) without SMTP: a user signing in via OIDC/GitHub/Google for the first time when an email-matching local account already exists is no longer auto-linked. They are sent to a password-challenge page where entering their existing Dawarich password completes the linking. No SMTP setup is required for this path. A "send me a confirmation email instead" button on the same page is the SMTP-based fallback for users who have forgotten their password.
- Self-hosted Immich/PhotoPrism URLs: the next save of these settings re-validates the URL. Configurations using non-http schemes,
0.0.0.0, multicast IPs, or the cloud-metadata169.254.169.254will be rejected. Standard LAN / Docker / loopback URLs continue to work.
Fixed
- Google Phone Takeout
location-history.jsonnow imports reliably. (#2437, #2587) - KMZ files from a wider range of exporters now import.
- Imports no longer fail intermittently with
No such file or directory @ rb_sysopen - /tmp/.... (#2446) - FIT files from non-Garmin devices and phone apps now import.
- CSV files with quoted headers (e.g.
"Latitude","Longitude") are now recognized. - Empty (0-byte) uploads now produce a clear error instead of crashing.
- Upgrades from older versions (≤ 1.3.1) no longer crash during
db:migrate. (#2576)
💙 This release is supported by Steven B., James Manolios, chenrik, aldumil, derpderpington, Chippie, dint, jhalpern, Lex Fradski, Schlufo, cyberswan.at, craftyklaus, Andre, hogenf, naraxius, Embrace, martin4861, Alex, evetters, GregF, Jon Coffee, Lukas, Robbie G, Kilian, Hans G, Chris, tabaha, Andre, Michael C, Chris, Jonah B., Dante, daallex, Tanner A., Milien M., Mathias, Travis S., Michael J., Matthew F., Johnathan D., bleibdirtroy, no1etal, dixet, Bailey J., Alex D., Benjamin M., Daniel A., Florian, BeeHappy, ChemistryDachshund, OrangeWindies, Michelangelo V., Edward, Erazem Z., Denis Abt, Tony G., Andrew D., Lomky, Osamu Y., Simon van B., Linus T., Christian C., Sebastian, Jan K., Nathan T., Max G., Lars N., Karol B., Konstantin, Johannes H., t3hero, g3lin, Tim, Philipp M., Brand K., Pablo F. M., Jon H., fkB, Mikael, Dániel A., Hai_Tsung, ShooTex, GreenTentacle, PinkahPandah, David, Ken, Denna G., Andre, Hendl91, Jon H., MrRed, Arkadiusz Z., Jake, Bator T., Alex J. H., eps-dev, twiggu, Dragan V., Jerome G., Carsten M., Sheya B., ArnyminerZ, Gustav B., higgs01, Frank F., F. J. Kruz, Jon D., Alexander J. H., Daniel D., Gonzalo M., Ricardo T., Christof Z., Abc123, Narrator, JohnSmith21, smartbert, A.M., Matthew Z., Dror T., Jonathan K. on Patreon and KoFi 💙
What's Changed
- Fix support for existing import formats, add detection for unsupporte… by @Freika in #2584
- feat: enable Sentry Logs with Rails.logger broadcast by @Freika in #2586
- Security audit fixes — C-1, C-2, C-3, H-1, H-2, M-1, M-3, M-4, L-1, L-3 by @Freika in #2585
- Send user creating webhook to Manager on all cloud signups, including… by @Freika in #2589
- 1.7.3 by @Freika in #2580
Full Changelog: 1.7.2...1.7.3