Vulnerability DatabaseGHSA-28xv-9wpg-c42r

GHSA-28xv-9wpg-c42r: 
Python vulnerability analysis and mitigation

Problem

Code read at bf7eb2c (v1.12.7). Found in an external security review (Oct 2026). The hosted Semantic Layer client picks the host and the token independently, then sends the token to that host:

  • connect.py:2204: host = env.get("DBT_SL_HOST") or getattr(semantic, "host", None), so semantic.host from .dex/config.yml is used whenever DBT_SL_HOST is unset.
  • connect.py:2213: token = env.get("DBT_SL_TOKEN") or _dbt_cloud_service_token(env) (the latter reads ~/.dbt/dbt_cloud.yml).
  • explore/semantic/hosted.py:157: self._url = f"https://{host}/api/graphql".
  • explore/semantic/hosted_transport.py:16-29: post_graphql POSTs with Authorization: Bearer {token}. Nothing checks that the host belongs to dbt Cloud (config.py SemanticConfig.host takes any value).

Impact

.dex/config.yml lives in the repository. A repository that sets semantic.host to a server it controls receives the user's dbt Cloud service token the first time anyone runs explore semantic --api in it. Typical cases: a cloned third-party project, a fork, or a PR an agent is reviewing. The token comes from the user's environment or home directory, not from the repository. The ~/.dbt/dbt_cloud.yml fallback may hold a full dbt Cloud API token rather than a Semantic-Layer-only one (see the _dbt_cloud_service_token docstring), which widens the blast radius. The source= path (host-supplied config and token) is not affected.

Proposal

  1. Bind host to token: refuse, before reading any token, a host that is not *.getdbt.com (suffix match on the parsed hostname, so regional and multi-tenant hosts such as sl.cloud.getdbt.com keep working; also localhost for tests).
  2. Repeat the same check at the top of post_graphql, so no other caller can send the Bearer elsewhere.
  3. Single-tenant custom domains, if supported, come only from an explicit exact-host list that lives with the token's source (user-level config or env), never from repo-level .dex/config.yml.
  4. Optional: accept DBT_SL_TOKEN_FILE (refused unless mode 0600) as an alternative to the env var.

Acceptance

  • With semantic.host: attacker.example and a token present, no outbound request is made, and the refusal names the host.
  • sl.cloud.getdbt.com (the existing test fixture) and regional *.getdbt.com hosts still work.
  • The token is not read when the host is refused.

Update 2026-10-21: second external review, re-checked at 6f94352 (main)

Still present on main. Three additions:

  1. The allowlist must include dbt.com, not only getdbt.com. references/semantic-layer.md:397 documents host: <account>.semantic-layer.<region>.dbt.com, so a *.getdbt.com-only check would break the documented form. Compare host == s or host.endswith("." + s) (a bare endswith("dbt.com") admits evildbt.com) on a lowercased hostname with any trailing dot stripped, and refuse /, @, : and whitespace, since hosted.py:157 interpolates the host into the URL as-is (evil.example/x? carries a path).
  2. The token fallback can pick an unrelated account. When the active project is not found, _dbt_cloud_service_token returns the token-value of the first project in ~/.dbt/dbt_cloud.yml, possibly for a dbt Cloud account the user never pointed dex at. Consider refusing instead of falling back.
  3. The source= path is safe only if the embedding host controls the config. With a SemanticSource, the host still comes from the passed config's semantic.host. Apply the same host check there, with the escape hatch for private-link hosts settable only by the embedding host (a DexEngine parameter), never by .dex/config.yml. The project already treats .dex/config.yml as possibly agent-written (values-free mode cannot be selected from it, "since an agent may have written that file"), which puts a hostile config inside the threat model.

Credits

Reported by Sthenos Security. Reported by Sthenos Security, found with Reachable. Fixed in exmergo-dex-core 1.16.1.


Source: NVD

Related Python vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-mpqx-q82w-9x46HIGH7.5
  • Python logoPython
  • graphql-core
NoYesOct 25, 2026
GHSA-4gm2-62xx-xwvxMEDIUM5.3
  • Python logoPython
  • aynops
NoYesOct 25, 2026
GHSA-jm75-qwf5-vg52MEDIUMN/A
  • Python logoPython
  • exmergo-dex-core
NoYesOct 25, 2026
GHSA-f3jf-cv9h-7c3gHIGHN/A
  • Python logoPython
  • exmergo-dex-core
NoYesOct 25, 2026
GHSA-28xv-9wpg-c42rHIGHN/A
  • Python logoPython
  • exmergo-dex-core
NoYesOct 25, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management