Upgrading python-dotenv 0.21 to 1
Breaking0.21.1 → 1.2.4Breaking3Security1Platform4New2Changed8Fixed16Other22
SecurityMedium · CVSS 6.6python-dotenv reads key-value pairs from a .env file and can set them as environment variables. Prior to version 1.2.2, `set_key()` and `unset_key()` in python-dotenv follow symbolic links when rewriting `.env` files, allowing a local attacker to overwrite arbitrary files via a crafted symlink when a cross-device rename fallback is triggered. Users should upgrade to v.1.2.2 or, as a workaround, apply the patch manually.GHSA-mf9w-mj56-hr94 · CVE-2026-28684 ↗
BreakingUpgrade verdict
2 breaking changes and 4 platform requirement changes and a security fix.
In plain terms
- Editing a .env file that is a symlink now changes the link itself rather than the file it points to, unless you opt in.
- Editing a .env file no longer changes its permissions; the existing permissions are kept.
- The package now works on the newest Python version, including its experimental no-GIL build.
- Adds support for Python 3.9.
Must act Top 5 of 7 that need code or config changes
Python requirement changed in 1.2.2: >=3.7 → >=3.10.
What you must change
Breaking2
dotenv.set_key and dotenv.unset_key no longer follow symlinks in some situations; use follow_symlinks=True to restore the old behavior.dotenv.set_keydotenv.unset_keyfollow_symlinksset_key, unset_key and CLI set/unset now preserve the original file mode instead of resetting it to 0o600; 0o600 is used only for new or non-regular files.dotenv.set_keydotenv.unset_keysetunsetSecurity1
python-dotenv reads key-value pairs from a .env file and can set them as environment variables. Prior to version 1.2.2,
Medium · CVSS 6.6set_key() and unset_key() in python-dotenv follow symbolic links when rewriting .env files, allowing a local attacker to overwrite arbitrary files via a crafted symlink when a cross-device rename fallback is triggered. Users should upgrade to v.1.2.2 or, as a workaround, apply the patch manually.Platform4
Adds support for Python 3.14, including the free-threaded (3.14t) build.
Adds support for Python 3.9.
Adds support for Python 3.13 and drops Python 3.8.
Drops support for Python 3.7 and adds Python 3.12-dev to the test matrix.
API changes
Generated by DepDelta from published Python source. Not mixed with prose notes.
- removed:
function list(ctx: click.Context, format: bool) -> None - removed:
function set(ctx: click.Context, key: Any, value: Any) -> None - changed:
function run(ctx: click.Context, override: bool, commandline: List[str]) -> None → function run(ctx: click.Context, override: bool, commandline: tuple[str, ...]) -> None - changed:
function run_command(command: List[str], env: Dict[str, str]) -> int → function run_command(command: List[str], env: Dict[str, str]) -> None - added:
function enumerate_env() -> Optional[str] - added:
function list_values(ctx: click.Context, output_format: str) -> None - added:
function set_value(ctx: click.Context, key: Any, value: Any) -> None
- changed:
function rewrite(path: StrPath, encoding: Optional[str]) -> Iterator[Tuple[IO[str], IO[str]]] → function rewrite(path: StrPath, encoding: Optional[str], follow_symlinks: bool=…) -> Iterator[Tuple[IO[str], IO[str]]] - changed:
function set_key(dotenv_path: StrPath, key_to_set: str, value_to_set: str, quote_mode: str=…, export: bool=…, encoding: Optional[str]=…) -> Tuple[Optional[bool], str, str] → function set_key(dotenv_path: StrPath, key_to_set: str, value_to_set: str, quote_mode: str=…, export: bool=…, encoding: Optional[str]=…, follow_symlinks: bool=…) -> Tuple[Optional[bool], str, str] - changed:
function unset_key(dotenv_path: StrPath, key_to_unset: str, quote_mode: str=…, encoding: Optional[str]=…) -> Tuple[Optional[bool], str] → function unset_key(dotenv_path: StrPath, key_to_unset: str, quote_mode: str=…, encoding: Optional[str]=…, follow_symlinks: bool=…) -> Tuple[Optional[bool], str]