Update dependency python-dotenv to v1.2.2 [SECURITY]#256
Update dependency python-dotenv to v1.2.2 [SECURITY]#256renovate[bot] wants to merge 1 commit intomainfrom
Conversation
|
|
||
| [[package]] | ||
| name = "python-dotenv" | ||
| version = "1.0.1" | ||
| version = "1.2.2" | ||
| description = "Read key-value pairs from a .env file and set them as environment variables" | ||
| optional = false | ||
| python-versions = ">=3.8" | ||
| python-versions = ">=3.10" | ||
| files = [ | ||
| {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, | ||
| {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, | ||
| {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, | ||
| {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, | ||
| ] | ||
|
|
||
| [package.extras] |
There was a problem hiding this comment.
🔴 This PR only updates python/poetry.lock to pin python-dotenv 1.2.2, but leaves python/pyproject.toml with python-dotenv = "^1.0.0", which allows any version >=1.0.0,<2.0.0. If the lock file is ever regenerated (via poetry lock, poetry update, or CI), Poetry can legally resolve to 1.0.1–1.2.1, all of which contain CVE-2026-28684 (symlink-following arbitrary file overwrite). Update python/pyproject.toml to python-dotenv = ">=1.2.2" to permanently enforce the minimum safe version.
Extended reasoning...
What the bug is and how it manifests
This PR patches CVE-2026-28684 by updating python/poetry.lock to pin python-dotenv at 1.2.2. However, the semver constraint in python/pyproject.toml remains python-dotenv = "^1.0.0" (in [tool.poetry.group.dev.dependencies]). The caret constraint ^1.0.0 allows Poetry to resolve any version >=1.0.0,<2.0.0. The lock file is only a snapshot; it does not permanently enforce a minimum version floor.
The specific code path that triggers it
If any developer or CI system runs poetry lock, poetry update python-dotenv, or regenerates the lock file for any reason, Poetry will re-resolve the dependency graph using only the constraint in pyproject.toml. Since ^1.0.0 permits 1.0.1, 1.1.0, 1.2.0, and 1.2.1 — all of which are vulnerable — Poetry may legally install any of those versions, silently reverting the security fix.
Why existing code does not prevent it
The lock file python/poetry.lock records the exact version resolved at a point in time (1.2.2), but Poetry treats the lock file as a reproducibility aid, not a security policy. The authoritative source of truth for what versions are acceptable is pyproject.toml. Without a tightened lower bound there, the lock file pin provides only ephemeral protection that disappears the next time dependencies are refreshed.
Impact
Any regeneration of the lock file could silently introduce a vulnerable version of python-dotenv. This is especially dangerous in CI pipelines that run poetry update or poetry lock before tests, in developer onboarding flows, and in Dependabot/Renovate workflows that refresh other dependencies. A vulnerable version allows a local attacker to exploit set_key()/unset_key() to overwrite arbitrary files via a crafted symlink (CVSS 6.6, integrity/availability impact).
Comparison with other locations in the repo
The other two locations in the repository handle this correctly: chart_data_extractor/pyproject.toml already uses python-dotenv = "^1.2.1" and template/requirements-dev.txt pins to python-dotenv==1.2.2. Only python/pyproject.toml is missing the constraint tightening.
Step-by-step proof
- Current state:
python/pyproject.tomlcontainspython-dotenv = "^1.0.0"andpython/poetry.lockpins version 1.2.2. - Developer runs
poetry updateorpoetry lock --no-updatein thepython/directory. - Poetry re-resolves all constraints. Since
^1.0.0is satisfied by 1.0.1, 1.1.0, 1.2.0, or 1.2.1, Poetry may select any of these depending on other constraints, available releases, or resolution order. - The lock file is now updated to a vulnerable version (e.g., 1.0.1), without any warning.
- CI installs the vulnerable version; the symlink-following CVE-2026-28684 is now present in the deployed application.
- Fix: Change
python/pyproject.tomlline topython-dotenv = ">=1.2.2"(or"^1.2.2"). This ensures Poetry will never resolve a version below the patched release, regardless of lock file state.
This PR contains the following updates:
1.0.1→1.2.2python-dotenv: Symlink following in set_key allows arbitrary file overwrite via cross-device rename fallback
CVE-2026-28684 / GHSA-mf9w-mj56-hr94
More information
Details
Summary
set_key()andunset_key()in python-dotenv follow symbolic links when rewriting.envfiles, allowing a local attacker to overwrite arbitrary files via a crafted symlink when a cross-device rename fallback is triggered.Details
The
rewrite()context manager indotenv/main.pyis used by bothset_key()andunset_key()to safely modify.envfiles. It works by writing to a temporary file (created in the system's default temp directory, typically/tmp) and then usingshutil.move()to replace the original file.When the
.envpath is a symbolic link and the temp directory resides on a different filesystem than the target (a common configuration on Linux systems using tmpfs for/tmp), the following sequence occurs:shutil.move()first attemptsos.rename(), which fails with anOSErrorbecause atomic renames cannot cross device boundaries.shutil.move()falls back toshutil.copy2()followed byos.unlink().shutil.copy2()callsshutil.copyfile()withfollow_symlinks=Trueby default.An attacker who has write access to the directory containing a
.envfile can pre-place a symlink pointing to any file that the application process has write access to. When the application (or a privileged process such as a deploy script, Docker entrypoint, or CI pipeline) callsset_key()orunset_key(), the symlink target is overwritten with the new.envcontent.This vulnerability does not require a race condition and is fully deterministic once the preconditions are met.
Impact
The primary impacts are to integrity and availability:
.env-formatted content controlled by the attacker.set_key(), the attacker can leverage this to write to files beyond their own access level.The scope of impact depends on the application using python-dotenv and the privileges under which it runs.
Proof of Concept
The following script demonstrates the vulnerability. It requires
/tmpand the user's home directory to reside on different devices (common on systemd-based Linux systems with tmpfs).Expected output:
Remediation
The fix changes the
rewrite()context manager in the following ways:.envpath is a symlink,rewrite()now resolves it to the real path before proceeding, or (by default) operates on the symlink entry itself rather than the target.follow_symlinks: bool = Falseparameter is added toset_key()andunset_key()for users who explicitly need the old behavior..envfile (instead of the system temp directory), eliminating the cross-device rename condition entirely.os.replace()is used instead ofshutil.move(), providing atomic replacement without symlink-following fallback behavior.Users are advised to upgrade to the patched version as soon as it is available on PyPI.
Timeline
rewrite()Patches
Upgrade to v.1.2.2 or use the patch from https://github.com/theskumar/python-dotenv/commit/790c5c02991100aa1bf41ee5330aca75edc51311.patch
Severity
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
theskumar/python-dotenv (python-dotenv)
v1.2.2Compare Source
Added
Changed
dotenv runcommand now forwards flags directly to the specified command by [@bbc2] in [#607]Fixed
set_keyandunset_keybehavior when interacting with symlinks by [@bbc2] in [790c5c0]Breaking Changes
dotenv.set_keyanddotenv.unset_keyused to follow symlinks in somesituations. This is no longer the case. For that behavior to be restored in
all cases,
follow_symlinks=Trueshould be used.In the CLI,
setandunsetused to follow symlinks in some situations. Thisis no longer the case.
dotenv.set_key,dotenv.unset_keyand the CLI commandssetandunsetused to reset the file mode of the modified .env file to
0o600in somesituations. This is no longer the case: The original mode of the file is now
preserved. Is the file needed to be created or wasn't a regular file, mode
0o600is used.v1.2.1Compare Source
pyproject.toml, removedsetup.cfg.envfrom FIFOs (Unix) by [@sidharth-sudhir] in [#586]v1.2.0Compare Source
buildandpyproject.tomlby [@EpicWink] in [#583]load_dotenv()usingPYTHON_DOTENV_DISABLEDenv var. by [@matthewfranglen] in [#569]v1.1.1Compare Source
Fixed
find_dotenvwork reliably on python 3.13 by [@theskumar] in [#563]v1.1.0Compare Source
Added
dotenv run, switch toexecvpefor better resource management and signal handling ([#523]) by [@eekstunt]Fixed
find_dotenvandload_dotenvnow correctly looks up at the current directory when running in debugger or pdb ([#553] by [@randomseed42])Misc
Configuration
📅 Schedule: (in timezone UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.