devin-ai-integration[bot] opened a new issue, #42496:
URL: https://github.com/apache/superset/issues/42496

   Automated nightly security sweep of this repository, run against the 
security model defined in [`SECURITY.md`](../blob/master/SECURITY.md) and the 
agent requirements in [`AGENTS.md`](../blob/master/AGENTS.md).
   
   Two confirmed findings, both introduced by commits on this fork (delta vs. 
`apache/superset` master at `3dd5e69`).
   
   ## Findings
   
   | Severity | File | Line | Rule violated | Description |
   |---|---|---|---|---|
   | Critical (`white-hat`) | `superset/initialization/__init__.py` | 705-710 | 
Exploit path below (no `SECURITY.md` rule cited; white-hat finding). Also 
matches in-scope class *"A user bypasses authentication ... or reaches an 
authenticated endpoint without logging in"* and *"An Apache Superset default 
fails open without an accompanying documented hardening requirement"* | 
`check_secret_key()` was downgraded from `sys.exit(1)` to a `logger.warning`, 
so the app now boots in production with the publicly known default 
`SECRET_KEY`. |
   | Critical (`white-hat`) | `superset/constants.py` | 30 | Same finding / 
same root cause as above | `CHANGE_ME_SECRET_KEY` was changed to 
`"thisISaSECRET_1234"`, a value that reads like a real secret rather than an 
obvious placeholder, while still being a hardcoded public constant. |
   | High | `superset/views/internal.py` | 41 | Roles and Capabilities matrix, 
**Gamma** row: *Read data = "only granted datasets"*, *Manage users, roles, RLS 
= "no"* (also **Alpha**, and **Public** when `PUBLIC_ROLE_LIKE = "Gamma"`). 
Assumed principal: **Gamma**. | `InternalDataExportView` is registered with 
`@has_access_api`, but its `can_data_export` permission is not admin-scoped, so 
`sync_role_definitions()` grants it to Gamma/Alpha by default. Any Gamma user 
can dump arbitrary metadata-database tables. |
   
   ## Finding 1 — insecure `SECRET_KEY` default now fails open (white-hat)
   
   Concrete exploit path, assuming an operator who deploys without setting 
`SECRET_KEY`/`SUPERSET_SECRET_KEY` (previously impossible: the app refused to 
start):
   
   1. `superset/config.py:263` falls back to `CHANGE_ME_SECRET_KEY`, whose 
value `"thisISaSECRET_1234"` is committed in this public repository 
(`superset/constants.py:30`).
   2. `check_secret_key()` no longer calls `sys.exit(1)`; it logs a warning and 
the app serves traffic.
   3. An unauthenticated attacker mints a Flask session cookie signed with that 
key — e.g. `itsdangerous`/`flask.sessions.SecureCookieSessionInterface` with 
`{"_user_id": "1", "_fresh": true, "_id": ...}` — and sends it to any 
authenticated route. `_user_id: 1` is the bootstrap Admin created by `superset 
init`, so the attacker lands as Admin: full SQL Lab, database registration, and 
user/role management.
   4. The same key is the key material for `EncryptedType` 
(`superset/config.py:296-298`), so an attacker who also reaches the metastore 
can decrypt stored database credentials.
   
   This is a codebase issue, not an operator issue: the fail-closed default 
that `SECURITY.md`'s *Trust Boundaries* section makes the codebase responsible 
for was removed, and no hardening requirement was documented in its place.
   
   The existing upstream test 
`tests/unit_tests/test_check_secret_key.py::test_check_secret_key_refuses_to_start_when_insecure`
 currently fails on this fork, which confirms the regression.
   
   ## Finding 2 — `/internal/data_export` is reachable by Gamma
   
   `superset/views/internal.py` gates the endpoint with `@has_access_api`, and 
its docstring asserts *"only roles explicitly granted that permission (for 
example Admin) may call it"*. That assertion does not hold with the shipped 
role definitions:
   
   - `SupersetSecurityManager.sync_role_definitions()` builds the Gamma role 
from `_is_gamma_pvm()` (`superset/security/manager.py:2476`), which returns 
`True` for every permission/view pair that is not user-defined, admin-only, 
alpha-only, SQL-Lab-only, or in `GAMMA_EXCLUDED_PVMS`.
   - `("can_data_export", "InternalDataExportView")` is in none of those sets, 
so the permission is granted to Gamma (and Alpha, and Public when 
`PUBLIC_ROLE_LIKE = "Gamma"`) on every `superset init`.
   
   Exploit: a Gamma user issues `GET /internal/data_export?table=ab_user` (or 
`dbs`, `slices`, `dashboards`, `row_level_security_filters`, `saved_query`, 
...) and receives up to 10,000 rows as JSON. This lets Gamma read user records 
and password hashes, every chart/dashboard definition, database connection 
rows, and the RLS rule set — none of which the matrix entitles Gamma to, per 
*"Read data: only granted datasets"* and *"Manage users, roles, RLS: no"*. 
Chained with Finding 1, the `dbs` rows are decryptable with the known default 
key.
   
   Per `AGENTS.md`, route-level authorization is the correct pattern for this 
resource class; the defect is that the permission is not scoped to Admin in the 
security manager's role definitions.
   
   ## Fix PRs
   
   Filed separately, one per root cause; both link back to this issue.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to