Skip to content

Don't modify the configured decode algorithms - #584

Open
M0nd0R wants to merge 1 commit into
vimalloc:mainfrom
M0nd0R:decode-algorithms-no-config-mutation
Open

M0nd0R wants to merge 1 commit into
vimalloc:mainfrom
M0nd0R:decode-algorithms-no-config-mutation

Conversation

@M0nd0R

@M0nd0R M0nd0R commented Oct 16, 2026

Copy link
Copy Markdown

_Config.decode_algorithms appended this application's encode algorithm to the list object stored in
app.config["JWT_DECODE_ALGORITHMS"] instead of to a copy of it. Because that list is held by
reference — app.config.from_object() copies attributes by reference, so applications built from the
same object share one list — the append widened the configured algorithm allowlist for the application
and for every other application sharing it.

class SharedCfg:
    JWT_SECRET_KEY = "s3cret"
    JWT_DECODE_ALGORITHMS = ["RS256"]   # operator: only RS256 may be decoded
    JWT_ALGORITHM = "RS256"

appA = Flask("A"); appA.config.from_object(SharedCfg)
appA.config["JWT_ALGORITHM"] = "HS256"          # appA legitimately encodes with HS256
JWTManager(appA)
with appA.app_context():
    config.decode_algorithms                    # ['RS256', 'HS256']

SharedCfg.JWT_DECODE_ALGORITHMS                 # ['RS256', 'HS256']  <- operator's list mutated

appB = Flask("B"); appB.config.from_object(SharedCfg)
JWTManager(appB)
with appB.app_context():
    config.decode_algorithms                    # ['RS256', 'HS256']  <- appB never configured HS256

appB is configured for RS256 only, yet it now accepts HS256 tokens. Once appended, the entry is
permanent: the list now contains the algorithm, so the not in test is false from then on and the
allowlist can no longer be narrowed back by resetting JWT_DECODE_ALGORITHMS.

The fix copies the configured list before appending. The behaviour that
test_missing_algorithm_in_decode_algorithms pins is unchanged — the encode algorithm is still
included in what the property returns; it is simply no longer written back into the configuration.

Cases with JWT_DECODE_ALGORITHMS unset or empty still resolve to [JWT_ALGORITHM] as before.

_Config.decode_algorithms appended this application's encode algorithm to
the list object stored in app.config["JWT_DECODE_ALGORITHMS"] instead of to
a copy of it.

That list is held by reference, and app.config.from_object() copies
attributes by reference, so applications built from a common config object
share a single list. Appending therefore added the algorithm of whichever
application touched the property first to the algorithms every other
application accepts. For example an application configured with
JWT_DECODE_ALGORITHMS = ["RS256"] and JWT_ALGORITHM = "RS256" accepts HS256
tokens once an application sharing that config object encodes with HS256.

The widening is permanent: once the algorithm is in the list the "not in"
test is false from then on, so resetting JWT_DECODE_ALGORITHMS no longer
restores the restriction.

Copy the configured list before appending. The behaviour that
test_missing_algorithm_in_decode_algorithms pins is unchanged: the encode
algorithm is still returned by the property, it is just no longer written
back into the configuration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant