Graphql Introspection in Chi with Basic Auth
Graphql Introspection in Chi with Basic Auth — how this specific combination creates or exposes the vulnerability
GraphQL introspection allows clients to query the schema type system for names, fields, and relationships. When a Chi service exposes a GraphQL endpoint without proper access controls and also uses HTTP Basic Authentication for an unauthenticated or partially authenticated path, introspection can be leveraged to map the API surface even when credentials are required for other operations.
Chi is a routing and middleware library for Clojure web applications. If a route handling GraphQL queries does not validate authorization before resolving introspection queries, an attacker who can supply Basic Auth credentials (or no credentials at all, depending on how Chi is configured) can send an introspection request and receive the full schema. This becomes an information disclosure issue because the schema reveals types, queries, and potentially sensitive business logic.
In this combination, the risk is that Basic Auth may be applied inconsistently—perhaps only to certain routes or handled via a middleware that does not block introspection. An attacker can probe the endpoint with an OPTIONS or GET request containing the Authorization header, or omit it to see whether introspection is allowed anonymously. Because GraphQL introspection is a standard feature, it is enabled by default in many libraries unless explicitly disabled. The scanner checks for unauthenticated introspection by sending an introspection query and analyzing whether the response contains schema details, which maps to findings in Input Validation and Authentication categories.
When scanning such a setup, middleBrick runs unauthenticated checks against the endpoint, attempting to retrieve the schema via a POST body with an introspection query while supplying a dummy Basic Auth header or none. If the endpoint returns schema data, the test flags it as a potential BOLA/IDOR or authentication bypass depending on how the routes are guarded. This highlights the need to either disable introspection in production or enforce authentication before the GraphQL handler is invoked.
Basic Auth-Specific Remediation in Chi — concrete code fixes
To secure a Chi GraphQL endpoint when using Basic Authentication, ensure that authorization checks occur before the GraphQL middleware resolves queries, and explicitly disable introspection in production environments.
Below is a concrete Chi route example with Basic Auth validation and introspection disabled. The middleware checks the Authorization header against a predicate and returns a 401 if missing or invalid. The GraphQL middleware is wrapped so that introspection queries are rejected before reaching the schema resolution logic.
(ns my-app.core
(:require [compojure.core :refer [defroutes GET POST]]
[ring.util.response :refer [response unauthorized-response]]
[cheshire.core :as json]
[graphql-clj.core :as graphql]
[graphql-clj.schema :as schema]))
(defn valid-basic-auth? [header expected-user expected-pass]
(when header
(let [[_ user pass] (re-matches #"^Basic\s+(\S+)$" header)
[u p] [(some-> user java.util.Base64/getDecoder .decode String.)
(some-> pass java.util.Base64/getDecoder .decode String.)]
(and (= u expected-user) (= p expected-pass)))))
(defn wrap-basic-auth [handler expected-user expected-pass]
(fn [request]
(if (valid-basic-auth? (get-in request [:headers "authorization"])
expected-user expected-pass)
(handler request)
(unauthorized-response))))
(defn disable-introspection [query variables]
(when (and query
(or (clojure.string/includes? query "__schema")
(clojure.string/includes? query "__type")))
(throw (ex-info "Introspection disabled" {:status 400}))))
(def schema (schema/build-schema
"type Query { hello: String }"))
(def app
(-> (wrap-routes
(context "/api" []
(POST "/graphql" [request]
(let [{:keys [query variables]} (json/parse-string (slurp (:body request)) true)]
(disable-introspection query variables)
(-> (graphql/execute schema query nil variables)
json/generate-string
response))))
(wrap-basic-auth "admin" "s3cret"))
(wrap-params)))
Key points in this remediation:
- Basic Auth is validated in a dedicated middleware layer before any GraphQL processing.
- Introspection is blocked by inspecting the query string for
__schemaor__typekeywords and throwing an error; alternatively, use a GraphQL server setting to disable introspection if your library supports it. - The handler parses JSON from the request body, ensuring the query and variables are explicitly handled, which avoids accidental exposure via GET or malformed requests.
After applying such fixes, rerun the scan to confirm that introspection is no longer accessible and that the authentication check is consistently enforced across all GraphQL routes.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |