Flask 0.12.2 and Werkzeug 0.12.2 have been released. They contain the same
security bugfix for the safe_join
function in each package.
The problem only occurs if you are running your application on a Windows server.
David Lord initially found this bug (thanks!) and disclosed it to the other maintainers in a private email:
While going through PR #2059 about safe_join, I looked up Python's ntpath.join and discovered a vulnerability that safe_join on Windows doesn't cover.
https://docs.python.org/3/library/os.path.html#os.path.join: "
os.path.join("c:", "foo")
represents a path relative to the current directory on drive C:(c:foo)
"
safe_join('\\root\\path', 'd:', 'test.txt')
would break out of the trusted root directory and instead take the test file relative to the cwd on the d drive. This doesn't give completely arbitrary path access, since it's limited to the cwd, but it's still not good.
For the application developer this means that endpoints using safe_join
could
potentially be used to disclose arbitrary files in the server processes'
current working directory on Windows.
We strongly recommend upgrading to Flask 0.12.2 and Werkzeug 0.12.2, as this bug has been fixed there (Flask, Werkzeug).
A CVE has been requested on Tue, 16 May 2017 06:51:09 +0000
, the CVE CVE-2017-9088
was assigned.
We just released Werkzeug 0.12. Highlights from the changelog:
script
moduleWerkzeug's script module was deprecated since 2011. Deprecation slipped through the cracks, so we now additionally show large warnings at runtime. Head over to the bugtracker for the rest of the plan.
Password hashing now uses sha256
by default instead of
sha1
. On a related note,
certificates generated with the dev server are now signed with sha256
instead of md5
.
After a long time of no changes a new release, 2.9 codename “Derivation” of the Jinja template engine for Python is out. This change is probably the biggest release in Jinja2's history and it requires a bit of explanation of why it happened and why it happened now. But first let's cover the big changes in it.
This appears to be an under the hood change because it effectively just changes the internal algorithm that Jinja2 uses to map it's own scoping rules onto the Python interpreter's scoping rules but it has wide ranging consequences. The original tracking issue goes back to 2011 and was created as a long running TODO item. There were a few reasons why it was implemented this way but over the years it became clearer and clearer that the method chosen for mapping identifiers is just causing too many issues. The reason it was not changed was that the worries were too big that people accidentally relied on such bugs.
However with improved support for pinning to older versions of Python packages and the fact that people no longer use linux distribution provided packages much the worries about greater changes are heavily reduced. With Jinja 2.9 the identifier tracking was completely changed which should squash pretty much all the weird behaviors developers might have encountered and also enabled support for related improvements. In particular the new identifier tracking generalized the context behavior for includes and imports.
In the ideal case you won't notice anything other than that some constructs are possible now that caused errors in the past.
While Jinja2 supported Python 3 for years now it never really embraced functionality that the language provides on 3.x that it does not do on 2.x. Largely that is caused by the fact that we want templates to be compatible between 2.x and 3.x (this is true only for as long as template variables are restricted to ASCII characters). However 3.6 now added async generators which permits Jinja2 to fully support the async
and await
keywords on 3.6 and later.
In particular it means that you can now return coroutines from functions passed to Jinja2 templates and the template engine will automatically await them. Likewise all filters were updated to work with iterators as well as async iterators alike.
Additionally Jinja2 now emits generator_stop
as a future flag which means that accidentally emitting StopIteration
from a filter or other code will no longer cause the template to just stop rendering silently. This was enabled by PEP 479.
Jinja2 now has an internal policy configuration which permits one to centrally reconfigure behavior of filters and other things. While so far not much can be reconfigured it will greatly support future improvements. This also finally allows us to provide a default tojson
filter which previously was only available through Flask or other frameworks. Through the policy configuration the particular form of JSON serialization can be customized and replaced.
generator_stop
on supported Python versions
(Python 3.5 and later)map
and friends will now give better error messages if you forgot to
quote the parameter.truncate
filter to support better truncation in case
the string is barely truncated at all.tojson
filter from Flask to Jinja2
and hooked it up with the new policy framework.safe
by default.compiler.ascii_str
policy.foo is divisibleby 2 or foo is divisibleby 3
as you would expect.with context
and without context
.with
and autoescape
tags are now built-in.select_autoescape
function which helps configuring better
autoescaping easier.One of the reasons Jinja2 was lying largely dormant is that it's always scary to touch something so many people use. While bugs were known for quite some time it requires careful changes to not change all the template code out there. In particular once salt and ansible started using Jinja it became a big emotional burden to do changes on it.
However it turns out that emotional burden does not get smaller for as long as those bugs are in there. Going in and cleaning up the behavior actually turns out to be healthier in the long run. Now even if this release introduces regressions in behavior, the internal code quality is much improved and reasoning about the runtime and compiler is a lot easier now.
On a personal note I'm happy to see how popular Jinja has become and I hope that with this release it becomes more enjoyable to write Jinja templates.
Aside: if you are downloading Jinja2 you will actually pull 2.9.1 because there was a regression in 2.9 that was only found after releasing it. In an ironic twist it was found when this website attempted to render a complex template with Jinja 2.9 on the build server.
We just pushed out a new release for Jinja (2.8.1) which includes a security related fix. If you are using the Jinja2 sandbox you are encouraged to upgrade or alternatively manually further lock down the sandbox.
The core of the issue is that Python's string format method that was added to strings can be used to discover potentially dangerous values including configuration values:
>>> config = {'SECRET_KEY': '12345'} >>> class User(object): ... def __init__(self, name): ... self.name = name ... >>> user = User('joe') >>> '{0.__class__.__init__.__globals__[config]}'.format(user) "{'SECRET_KEY': '12345'}"
For this reason you must never let user supply format strings in raw Python as its too easy to escape them. However specifically for the Jinja2 sandbox we changed the behavior now that we're using the same sandboxing functionality that Jinja2 uses for its own runtime also for Python string formatting.
This means that with 2.8.1 and higher templates from sandboxed environments will intercept format strings the same way as with normal cases:
>>> from jinja2.sandbox import SandboxedEnvironment >>> env = SandboxedEnvironment() >>> class User(object): ... def __init__(self, name): ... self.name = name ... >>> t = env.from_string( ... '{{ "{0.__class__.__init__.__globals__}".format(user) }}') >>> t.render(user=User('joe')) Traceback (most recent call last): ... jinja2.exceptions.SecurityError: ...
If you don't want or you cannot upgrade Jinja2, you can override the is_safe_attribute
method on the sandbox and explicitly disallow all format
attributes on strings.
Thank you to Olivier Dony for reporting the issue.
Flask 0.12 has been released. This is not as big a step as 0.11 has been, the only intentionally backwards-incompatible change is with regards to send_file
's behavior, which, when invoked as send_file(f)
with f
being a file-like object, no longer guesses the MIME-type from f.name
. You have to pass a filepath instead.
Special thanks to Kyle Lawlor for fixing up most documentation after the flask
CLI got introduced.
--version
.send_file
has been removed, as per issue #104
. See pull request #1849
.send_file
now fails loudly and doesn't fall back to
application/octet-stream
. See pull request #1988
.flask.safe_join
able to join multiple paths like os.path.join
(pull request #1730
).#2006
).send_file
.app.test_client
includes preset default environment, which can now be
directly set, instead of per client.get
.After a very long, long waiting time Flask finally got a new release. There really was no good reason that there has not been a release in such a long time but unfortunately once things are postponed for too long a certain release anxiety kicks in.
In this case this was long tagged as 1.0 but we decided for renaming it to 0.11 and back out some of the more controversial changes. In particular the new command line interface for Flask was modified a bit to not depend on some specific functionality in the supporting Click library.
Highlights of this release are the improved development experience which now stalls the browser on reload instead of bringing up a "connection reset" page and the new command line support.
This is also the first Flask release under the new pallets organization and from now on we hope to bring you releases more frequently. Ideally with the next release we also update the website to find a new home for the showcase, flask extension list as well as the snippet section to allow the community to take care of those things themselves.
flask.jsonify
. This
introduces a security risk in ancient browsers. See
json-security
for details.**kwargs
to flask.Test.test_client
to support passing
additional keyword arguments to the constructor of
flask.Flask.test_client_class
.SESSION_REFRESH_EACH_REQUEST
config key that controls the
set-cookie behavior. If set to True
a permanent session will be
refreshed each request and get their lifetime extended, if set to
False
it will only be modified if the session actually modifies.
Non permanent sessions are not affected by this and will always
expire if the browser window closes.(response, headers)
from a view function.flask.Config.from_json
.flask.Flask.config_class
.flask.config.Config.get_namespace
.TEMPLATES_AUTO_RELOAD
config key.flask
command and the flask.cli
module to start the local
debug server through the click CLI system. This is recommended over the old
flask.run()
method as it works faster and more reliable due to a
different design and also replaces Flask-Script
.werkzeug.exceptions
). This makes it possible
for an extension author to create exceptions that will by default
result in the HTTP error of their choosing, but may be caught with
a custom error handler if desired.flask.Config.from_mapping
.LOGGER_HANDLER_POLICY
configuration key.EXPLAIN_TEMPLATE_LOADING
config flag which when enabled will
instruct Flask to explain how it locates templates. This should help
users debug when the wrong templates are loaded.request.json
in favour of request.get_json()
.OPTIONS
method is now correctly disabled if
the user registered an overriding rule with the lowercase-version
options
(issue #1288
).flask.json.jsonify
now supports the datetime.date
type (pull request
#1326
).#1393
).#1422
).flask.g
now has pop()
and setdefault
methods.flask.templating.render_template_string
by default
(pull request #1515
).flask.ext
is now deprecated (pull request #1484
).send_from_directory
now raises BadRequest if the filename is invalid on
the server OS (pull request #1763
).JSONIFY_MIMETYPE
configuration variable (pull request #1728
).Today we pushed out a Werkzeug bugfix release which contains a security relevant fix. It has come to our attention (reported by Jordan Milne) that the PIN brute-force protection in the Werkzeug debugger could be bypassed by attacking the cookie rather than the PIN. While this is generally not easily fixable we improved the situation by mixing in higher quality secret data into the cookie name and made it more complex. We now include a UUID of the machine the code is running on.
This should make it significantly more complex to bypass the PIN check. That said we want to reiterate that the PIN protection for the debugger is not a suitable protection to run the debugger in production. It's a basic security feature to make it less likely to use an accidentally enabled debugger. Please ensure that you never enable the debugger in production environments regardless of this feature.
On the first of April 2010, I released a joke microframework called denied which made fun of the fact that all microframeworks at the time decided to forgo with dependencies and bundle up everything they need in a single Python file. What I did was embed all of Jinja2 and Werkzeug in a base64 encoded zip file within the framework's only Python file. The response to it was interesting in a few ways because on the one hand quite a few people did not really understand that it was an April fools joke to begin with and on the other, there was a discussion where there were no microframeworks that actually did use dependencies and encouraged it.
One month later there was a new project by the name of "Flask" which actually gave this concept a real shot. It launched with the tagline "a microframework for Python based on Werkzeug, Jinja 2 and good intentions" and six years later it's the most starred Python framework on GitHub.
What's interesting about Flask is that its success just happened. There are no conferences about it, no society or foundation and still today much of it heavily depends on me directly. I'm not even sure why it became this successful but I attribute a lot of it to the fact that it's easy to get started and the full footprint of the framework is small enough that it becomes easy enough to understand.
So what's changing now? Today we launch the Pallets Projects. What is it? Primarily it's a GitHub organization which will be the home of Flask and all the associated projects. It will be a new home for those libraries and the first step to give the community more impact on the development of Flask and all libraries. In addition there will be a new release of Flask very soon after a thorough check that we do not break anything.
The people behind the Pallets Projects are me, Markus Unterwaditzer, David Lord and Adrian Mönnich with the organization being open for newcomers to help and drive the projects forward.
We will spend the next few weeks adding as much organizational information on the project's website to ensure that what often currently only exists in my head is brought down to text.
I'm amazed how many people use and love Flask and my libraries and I hope that this organization will be a good step towards making this scale past me. It's humbling how big all of this became.