Apache Superset is an open source data visualization and exploration tool. It has over 50K stars on GitHub, and there are more than 3000 instances of it exposed to the Internet. In our research, we found that a substantial portion of these servers – at least 2000 (two-thirds of all servers) – are running with a dangerous default configuration. As a result, many of these servers are effectively open to the public. Any attacker can “log in” to these servers with administrative privileges, access and modify data connected to these servers, harvest credentials, and execute remote code. In this post, we’ll dive deep into the misconfiguration, tracked as CVE-2023-27524, and provide advice for remediation as well as indicators of compromise to look for if you’re a user of Superset.
A Default Flask Secret Key
Superset is written in Python and based on the Flask web framework. A common practice for Flask-based applications is to use cryptographically signed session cookies for user state management. When a user logs in, the web application sends a session cookie that includes a user identifier back to the end user’s browser. The web application signs the cookie with a SECRET_KEY, a value that is supposed to be randomly generated and typically stored in a local configuration file. With every web request, the browser sends the signed session cookie back to the application. The application then validates the signature on the cookie to re-authenticate the user prior to processing the request.
The security of the web application depends critically on ensuring the
SECRET_KEY is actually secret. If the
SECRET_KEY is exposed, an attacker with no prior privileges could generate and sign their own cookies and access the application, masquerading as a legitimate user. The off-the-shelf flask-unsign tool automates this work: “cracking” a session cookie to discover if it was signed by a weak
SECRET_KEY, and then forging a fake but valid session cookie using a known
Back in October 2021, when we first started researching Superset, we noticed that the
SECRET_KEY is defaulted to the value
\x02\x01thisismyscretkey\x01\x02\\e\\y\\y\\h at install time. It’s the end user’s responsibility to modify the application configuration to set the
SECRET_KEY to a cryptographically secure random string. This is documented in the Superset configuration guide. But we were curious what percentage of users actually read the documentation. So, using Shodan, we did a basic search for Superset servers on the Internet. Simply requesting the Superset login page (without attempting to login) returns a session cookie that we then passed through
flask-unsign to determine if it was signed with the default
SECRET_KEY. To our surprise, we found that 918/1288 (> 70%) of all servers were using the default
SECRET_KEYfor a Superset application? Assuming the Superset server is not behind single sign-on (SSO), an attacker can login as an administrator by forging a session cookie with a
_user_idvalue set to 1, using the off-the-shelf
flask-unsigntoolkit. “1” corresponds to the first Superset user, who is almost always an administrator. Setting the forged session cookie in the browser’s local storage and refreshing the page allows an attacker to access the application as an administrator. For Superset servers behind SSO, more work may be required to discover a valid
user_idvalue – we have not tested this attack path.
Superset is designed to enable integrations with a variety of databases for exploring data and creating visualizations. Admin access gives attackers a lot of control over these databases and the ability to add and remove database connections. By default database connections are set up with read-only permissions but an attacker with admin access can enable writes and DML (data model language) statements. The powerful SQL Lab interface allows attackers to run arbitrary SQL statements against connected databases. Depending on database user privileges, attackers can query, modify, and delete any data in the database as well as execute remote code on the database server.
Remote Code Execution and Credential Harvesting
Administrative interfaces to web applications are often feature-rich and result in remote code execution on the application server. We found reliable paths to remote code execution across different Superset versions in a variety of configurations. Remote code execution is possible both on databases connected to Superset and the Superset server itself. We also found a host of methods for harvesting credentials. These credentials include Superset user password hashes and database credentials, both in plaintext and in a reversible format. We are not disclosing any exploit methods at this time, though we think it’ll be straightforward for interested attackers to figure it out.
More Default Flask Secret Keys
After our initial report to the Superset team back in Oct. 2021, we decided to re-check the state of Superset in Feb. 2023 to see if the situation with the default Flask key had improved.
We discovered that in January 2022 the
SECRET_KEY value was rotated to a new default
CHANGE_ME_TO_A_COMPLEX_RANDOM_SECRET, and a warning was added to the logs with this Git commit.
We were curious if this change translated to a change in user behavior. We repeated the Shodan experiment from October 2021, using both the original default
SECRET_KEY and the new one. We also included two other
SECRET_KEYs we found, one in a deployment template,
thisISaSECRET_1234, and another in the documentation
A basic search for Superset instances produced 3390 results, of which 3176 appeared to be really Superset instances. And of these 3176 instances, we found that 2124 (~67%) were using one of the four default keys.
The usage of Superset over the last year has increased, but the usage of a default
SECRET_KEY hasn’t dropped much. A large number of installs are using the new default
SECRET_KEY. To get extra precise, we did a sweep of Superset instances to grab their version information, which is often visible on the landing page. From this we got a breakdown of default keys in use by version: The rotation of the
SECRET_KEY and addition of the warning in the logs happened with version 1.4.1. It can be seen from version 1.4.1 onwards, a significant proportion of instances are sill running with a default key. For instance, 71% of Superset 2.0.0 instances and 55% of Superset 2.0.1 instances and 87% of the latest Docker version 0.0.0-dev instances are running with default keys.
The Superset team made an update with the 2.1 release to not allow the server to start up if it’s configured with a default
SECRET_KEY. With this update, many new users of Superset will no longer unintentionally shoot themselves in the foot.
This fix is not foolproof though as it’s still possible to run Superset with a default
SECRET_KEY if it’s installed through a docker-compose file or a helm template. The docker-compose file contains a new default
TEST_NON_DEV_SECRET that we suspect some users will unwittingly run Superset with. Some configurations also set admin/admin as the default credential for the admin user.
Among the 2000+ affected users, we found a broad mix of large corporations, small companies, government agencies, and universities. We sent out good-faith notifications to a number of organizations, some of whom remediated shortly after.
If you’re a user of Superset, you can check if your server is vulnerable with this script on Github. The script uses the
flask-unsign toolkit to check if the Superset session cookie is signed with one of the known default
If the script shows your Superset instance is vulnerable, and you have a Superset instance running on the Internet, we recommend that you fix immediately or remove it from the Internet.
Fixing the issue requires generating a
SECRET_KEY securely and configuring it, following the instructions here. In addition, since sensitive information such as database passwords is also encrypted with the
SECRET_KEY, that information will need to be re-encrypted with the new
superset CLI tool automates the process of rotating secrets – see here.
We have not validated exploitation against Superset installs with single sign-on (SSO) configured. SSO may make it hard to forge session cookies if the
user_ids are unpredictable GUIDs rather than auto-incrementing identifiers. At the same time, it’s possible there are other attack paths that leak user ids, or the user ids map to easily discoverable identifiers such as email addresses. We recommend remediating even if your Superset install is behind SSO.
Telling if you’ve already been compromised is not that easy because exploiting this misconfiguration allows anyone to masquerade as a legitimate user. Superset provides a detailed action log in the interface that can be used to inspect user activity. We recommend looking for unusual admin-level actions such as viewing or modifying database configuration, adding a new database,, exporting data, or unusual queries in the SQLLab query history. We also recommend looking at the application access log to check for unusual API calls such as calls to the
/api/v1/database endpoint. Of course an attacker can easily cover their tracks once they fully compromise the server.
The issue of hardcoded Flask secret keys is not new. Apache Airflow, a sister project to Superset, was affected by a similar issue, filed as CVE-2020-17526, discovered by Junghan Lee of Deliveryhero. Security researcher @iangcarroll automated discovery of vulnerable Airflow instances for bug bounty and wrote up a blog post describing the process here. The authentication bypass method he describes is exactly the same as what’s described above, as both Airflow and Superset are based off the same common framework, Flask AppBuilder.
Later on @iangcarroll found a similar vulnerability in Redash, another open source data visualization tool based on Flask. This was filed as CVE-2021-41192. The approach the Superset team took to addressing this vulnerability – refusing to start the server if it’s running with a default
SECRET_KEY – is the same approach the Redash team took.
It’s not often that data is available at scale to understand how security design choices impact user behavior. Checking for vulnerabilities and misconfigurations typically requires crossing ethical boundaries. In this case, we got lucky. Telling if a Superset server is misconfigured simply requires browsing to the login page and cracking the returned session cookie.
It’s commonly accepted that users don’t read documentation and applications should be designed to force users along a path where they have no choice but to be secure by default. The data we’ve gathered backs up this common wisdom. We all know that default credentials and default keys are bad, but how bad are they really? In the case of Superset, the impact of the insecure default Flask key extends to roughly 2/3 of all users. Again, users don’t read documentation. And users don’t read logs. The best approach is to take the choice away from users and require them to take deliberate actions to be purposefully insecure.
- Oct. 11, 2021: Initial communication to Apache Security team
- Oct. 12, 2021: Superset team says they will look into issue
- Jan. 11, 2022: Superset team changes default
SECRET_KEYand adds warning to logs with this Git commit
- Feb. 9, 2023: Email to Apache Security team about new data related to insecure default configuration. Started notifying certain organizations.
- Feb. 24, 2023: Superset team confirms code change will be made to address default
- Mar. 1, 2023: Pull request merged with code change to address default
- Apr. 5, 2023: Superset 2.1 release
- Apr. 24, 2023: CVE disclosed
- Apr. 25, 2023: This post
- Horizon3 Vuln Check/Exploit Script
- Configuring Superset
- Apache Superset on GitHub
- Flask Unsign Toolkit
- Apache Superset Pull Request to not Start Server if Running with default SECRET_KEY
- Flask Configuration Handling: SECRET_KEY
- Superset Deployment Template
- CVE-2023-27524: Superset Session Validation Vulnerability When Using Provided SECRET_KEY
- CVE-2020-17526: Airflow Authentication Bypass Misconfiguration
- CVE-2021-41192: Redash Authentication Bypass Misconfiguration