Ansible published ansible-core v2.20.9 on 8 September 2026 at 16:50:09 UTC. The change that reaches controller logs is mask_url: a URL with a password and no username, such as redis://:password@host, is rewritten so the password is no longer intact. The same tag rejects prefix and suffix on ansible.builtin.tempfile when those values contain a path separator.
The full release notes and downloads are on the GitHub release page. The release body is a pointer to the v2.20 changelog plus two artifacts with SHA256 sums. The v2.20.9 section is one minor change and eight bugfixes. Later headings in that file belong to earlier tags, v2.20.0 through v2.20.8.
URL modules mask credentials in results ¶
Five entries now mask authentication information in every display and in every return of URI data: apt_key, get_url, rpm_key, uri, and the url lookup.
get_url and uri download an artifact or call an HTTP endpoint. apt_key and rpm_key fetch a signing key from a URL. The url lookup runs during templating and often lands in a fact. A URL with credentials could copy that userinfo into callback output, a registered variable, and any store that keeps Ansible job text. v2.20.9 masks the authentication data on these paths. The request still sends the credentials. Masking covers what the controller prints and what the return contains.
The minor change is mask_url in module_utils, described as allowing masking of auth data embedded in URLs. On this tag the function lives in module_utils.urls and the mask token is ****. It returns the URL unchanged when both username and password are absent, so http://host/path stays http://host/path. When a password is present, username:password@ in the netloc becomes ****:****@. A username with no password becomes ****@. http://user:password@host/path comes back as http://****:****@host/path.
Password only URLs and error text ¶
mask_url now masks a password when the username is absent. The changelog example is redis://:password@host. Parsing yields an empty username and password password, with netloc :password@host. The replace pattern is :password@, and the result is redis://****:****@host. redis://:password@host/0 keeps the path and masks the userinfo. Before this tag that URL was returned unmasked.
module_utils.urls also masks inline URL authentication on errors. fetch_url writes mask_url into the info dict url field before the request, and on success replaces it with mask_url of the final URL from geturl. fetch_file puts mask_url in the Failure downloading message. The v2.20.9 section names no configuration key that disables the mask. Check that the password string is absent from the result. The token written on this tag is ****.
Tempfile prefix and suffix checks ¶
tempfile rejects prefix and suffix values that contain path components, to stop path traversal. On this tag that is ansible.builtin.tempfile. prefix defaults to ansible. and suffix defaults to empty. The module fails when the value differs from os.path.basename of itself. The messages are prefix must be a valid file name component and suffix must be a valid file name component, and they include the rejected value. The documentation requires both options to be file name components without path separators.
../build, dir/name, and foo/ fail that comparison. build and ansible. pass. A passing value still goes to mkstemp or mkdtemp. path selects the directory, or the system temporary directory when path is omitted. state remains file or directory.
A play that put a directory in prefix or suffix now fails the task. A single name fragment still returns a path. The URL changes in this tag alter strings in results and errors.
Upgrade notes ¶
The v2.20.9 section lists no removed options and no new required configuration. The release summary points at the 2.20 porting guide for the series. The patch bullets contain no migration procedure.
Two checks before installing this tag:
- Register a
uriorget_urlresult, and run theurllookup, on a URL with userinfo. The password should be absent from the display and the return. Repeat withredis://:password@host, the form named in the bugfix. - Run
ansible.builtin.tempfilewithprefixset to../buildand expectprefix must be a valid file name component. Run it again with prefixansible.and expect a returned path.
Published files: built distribution ansible_core-2.20.9-py3-none-any.whl at 2430540 bytes, SHA256 1ab5e75c4bb214a37e75f40f02dc545cdbbe2a322ef367cbb4451234c3cbe765, and source distribution ansible_core-2.20.9.tar.gz at 3349426 bytes, SHA256 73bcd4c3dd51b597202f8cf5a72b8e145342c7885ad21114e5979bdf629b3366. Both are linked from the GitHub release page. Check the SHA256 of the file you install.
Where to get it ¶
- Release page: GitHub release for v2.20.9
- Repository: ansible/ansible on GitHub
- Tag:
v2.20.9