fix(security): stop leaking live Jira/Tempo admin tokens in config export
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled

_REDACTED_KEYS listed jira.api_token/jira.password/tempo.api_token, but
routers/system.py actually writes admin credentials under
jira.admin_api_token and tempo.admin_token. The mismatch meant every
config export bundle included the live Jira and Tempo admin API tokens
in plaintext instead of redacting them. Found while researching the
Jira/Tempo integration for a service-account request; added a
regression test.
This commit is contained in:
kitos
2026-07-08 11:08:09 +02:00
parent 0b6a664651
commit df49d336f7
2 changed files with 26 additions and 1 deletions
+9 -1
View File
@@ -32,9 +32,17 @@ from app.models.webhook_config import WebhookConfig
router = APIRouter(prefix="/admin", tags=["admin"]) router = APIRouter(prefix="/admin", tags=["admin"])
# Keys whose values contain secrets and must be redacted in the export # Keys whose values contain secrets and must be redacted in the export.
# Must be kept in sync with the actual SystemConfig keys written by
# routers/system.py's _JIRA_KEYS map and the SMTP settings section —
# a stale/mismatched name here silently exports a live credential in
# plaintext instead of redacting it.
_REDACTED_KEYS = { _REDACTED_KEYS = {
"smtp.password", "smtp.password",
"jira.admin_api_token",
"tempo.admin_token",
# Older/alternate key names kept defensively in case a prior schema
# version wrote under these instead.
"jira.api_token", "jira.api_token",
"jira.password", "jira.password",
"tempo.api_token", "tempo.api_token",
@@ -46,6 +46,23 @@ def test_export_config_redacts_smtp_password(client, db, auth_headers):
assert values["smtp.host"] == "smtp.example.com" assert values["smtp.host"] == "smtp.example.com"
def test_export_config_redacts_live_jira_and_tempo_admin_tokens(client, db, auth_headers):
"""Regression test: the redaction key list previously named
jira.api_token/jira.password/tempo.api_token, which don't match the
actual keys routers/system.py writes (jira.admin_api_token,
tempo.admin_token) — so the live admin Jira/Tempo credentials were
exported in plaintext instead of being redacted."""
db.add(SystemConfig(key="jira.admin_api_token", value="ATATT-real-jira-token"))
db.add(SystemConfig(key="tempo.admin_token", value="real-tempo-token"))
db.commit()
body = client.get("/api/v1/admin/export-config", headers=auth_headers).json()
values = {r["key"]: r["value"] for r in body["system_configs"]}
assert values["jira.admin_api_token"] == "[REDACTED]"
assert values["tempo.admin_token"] == "[REDACTED]"
def test_export_config_never_exports_sso_private_key(client, db, auth_headers): def test_export_config_never_exports_sso_private_key(client, db, auth_headers):
db.add(SsoConfig(is_enabled=True, provider_name="Okta", sp_private_key="super-secret-key")) db.add(SsoConfig(is_enabled=True, provider_name="Okta", sp_private_key="super-secret-key"))
db.commit() db.commit()