Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset python/PYTHON-FLASK-SEC-018 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects Flask applications that initialize Hashids with Flask's secret key as the salt: Hashids(salt=app.secret_key). Hashids is a library for encoding integers into short URL-friendly strings. It is not a cryptographic hash function -- it is a bidirectional encoding scheme, and the salt is recoverable.
In 2015, security researcher Phil Carnage published a cryptanalysis showing that the Hashids salt can be recovered with approximately 20 known plaintext pairs (input integer and corresponding hashid). This means an attacker who observes enough hashids in your application's URLs can reverse-engineer the salt value. If the salt is Flask's secret_key, the attacker now has the key used to sign session cookies, CSRF tokens, and any other Flask security primitive that depends on SECRET_KEY. With the secret key, the attacker can forge arbitrary session cookies and authenticate as any user, including administrators.
The detection uses HashidsModule.method("Hashids").where("salt", "app.secret_key") -- a QueryType-based precise match. HashidsModule declares fqns=["hashids"], so only Hashids objects imported from the hashids package are matched. The .where("salt", "app.secret_key") filter means only calls where the salt keyword argument is specifically the Flask secret key attribute are flagged. Using a separate, dedicated salt value for Hashids does not trigger this rule. This precision delivers zero false positives on correctly configured applications.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Flask Secret Key Exposure via Hashids Cryptanalysis
With approximately 20 known (integer, hashid) pairs -- easily obtained from any paginated list, user profile URL, or content ID that exposes hashids -- an attacker can recover the Hashids salt through known-plaintext cryptanalysis. If that salt is app.secret_key, the attacker has the key used to sign everything Flask protects with it.
Session Cookie Forgery
Flask's session cookie is signed with SECRET_KEY using itsdangerous. Once an attacker obtains the secret key, they can forge a session cookie with any user ID -- including admin accounts -- without ever knowing a password or exploiting authentication logic.
CSRF Token Bypass
Flask-WTF's CSRF tokens are also derived from SECRET_KEY. With the key recovered, an attacker can generate valid CSRF tokens for any target user's session, bypassing CSRF protection on all state-changing endpoints.
Itsdangerous Token Forgery
Any itsdangerous-based token (password reset links, email confirmation tokens, timed tokens) that the application generates using SECRET_KEY can be forged by an attacker who possesses the key.
How to Fix
Recommended remediation steps
- 1Use a separate, independently generated value for the Hashids salt -- for example, an environment variable HASHIDS_SALT that is distinct from FLASK_SECRET_KEY.
- 2Rotate the Hashids salt independently of the Flask secret key so a compromise of one does not affect the other.
- 3Understand that Hashids is not a security primitive -- it is an obfuscation library. Do not rely on Hashids to protect access control. Always enforce authorization server-side regardless of whether the ID is encoded.
- 4If you need cryptographically secure token generation for URLs, use itsdangerous.URLSafeTimedSerializer with a dedicated signing key rather than Hashids.
- 5Store sensitive key material (secret keys, salts) in a secrets manager or environment variables, never hardcoded in source code.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule uses a QueryType-based precise match: HashidsModule.method("Hashids").where("salt", "app.secret_key"). HashidsModule declares fqns=["hashids"], restricting matches to objects imported from the hashids package. The .method("Hashids") step targets the Hashids() constructor call. The .where("salt", "app.secret_key") step filters to calls where the salt keyword argument is specifically the attribute access app.secret_key -- the Flask application's secret key. Using a variable that happens to equal the secret key at runtime, or using app.config["SECRET_KEY"] instead of app.secret_key, are separate patterns not covered by this precise match. The rule operates at the call-site level without cross-file dataflow analysis.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Frequently Asked Questions
Common questions about Flask Hashids with Secret Key as Salt
New feature
Get these findings posted directly on your GitHub pull requests
The Flask Hashids with Secret Key as Salt rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.