Security fixes are best-effort for:
- the latest code on
main - the most recent tagged release
Older snapshots may not receive fixes.
ChDash has no login page. The configuration requires an access block. The access block selects the model (docs/access.md):
mode = "authzen": An access gateway authenticates each human. It gives ChDash a signed identity token (EdDSA or ES256). ChDash verifies the token on each request to the pages and to the API. Without a valid token, ChDash returns401. ChDash asks an AuthZEN PDP for each action, on the service, on the host or on the database of the request. When the answer isfalse, or when the PDP does not answer, ChDash returns403. A run hasreadonly = 1if the user does not havequery.run.writeon its host. The pages show only the hosts on which the user holds an action. A request for another host gets the answer of a host that does not exist.mode = "open": Everyone who can reach the port has the ClickHouse rights of the configured accounts. ChDash writes a warning at each start. Use this mode only for a server that stands alone on a closed network and serves a trusted team.
- The people who reach the port in the open mode can run SQL as the runner user of each host. They can read the system tables through the system user. When MCP is on, they can manage the MCP keys from the page. In the authzen mode, the PDP checks each of these actions for each human.
- The access gateway and the PDP are trusted. A token signed with one of the configured keys identifies the human. The PDP gives all the permissions. Keep the private key of the gateway and the token of the PDP secret.
- A client that sends its own identity header is refused. The signature check refuses a token that the client made. The reverse proxy must replace the header that a client sends. ChDash refuses a request with two copies of the header. ChDash never reads the token from a cookie or a query parameter.
- Other web sites that a user opens in the same browser must not use ChDash through this browser. ChDash protects against this itself. Refer to "What ChDash does" below.
- The MCP clients reach only
POST /mcpwith a key. A key limits the tools, the hosts and the databases. The MCP user of ClickHouse limits the data.
- Do not expose ChDash to the Internet. Listen on a private address, or publish the port on
127.0.0.1only (examples/docker-compose.config.yml). - Put an access gateway in front of it when more than one person uses it. Use
access { mode = "authzen" }(docs/access.md). The gateway authenticates the human and gives the identity token. The reverse proxy replaces the identity header that a client sends. The proxy must keep theHostheader or setX-Forwarded-Host(the guard of the writes compares it withOriginfor older browsers). The proxy must not replace the security headers of ChDash. - Keep the PDP on a private network. ChDash has no TLS client, so it calls the PDP with
http. Limit the network between ChDash and the PDP to these two programs. - Terminate TLS in the proxy. ChDash serves plain HTTP. Add
Strict-Transport-Securityin the proxy. - Keep ClickHouse on a private network. ChDash talks to ClickHouse without TLS (
secure=1is refused). Put ChDash next to ClickHouse, or use a tunnel. - Give each ClickHouse account the least rights (docs/configuration.md, "Recommended ClickHouse account separation"):
- the runner:
SELECTon the databases that the panel shows,SHOWgrants, and no right to manage users. Do not giveKILL QUERY. The panel refusesKILL QUERYstatements, and ChDash cancels with the system user. Give write rights only when the panel must write. - the system user:
SELECTon thesystemtables that the pages read and on the OpenTelemetry tables, andKILL QUERYfor the cancel. The access audit lists the missing ones. - the MCP user: read only (
readonly = 1in its profile), andSELECTon the data that MCP may read.
- the runner:
- Run the container with the least privilege. Use a user that is not root, a read-only root file system, no capability and
no-new-privileges(examples/docker-compose.config.yml). Keep the password files separate from the configuration. Make them readable only by this user. - Keep
/metricsinternal. It shows host names and counts, never a password. It needs no identity token, as the probes do.
- Each answer has a Content-Security-Policy. The hash of each inline script of a page lets that script run. No other script runs. Each answer has
frame-ancestors 'none'andX-Frame-Options: DENY, which block the display of ChDash in a frame. Each answer hasX-Content-Type-Options: nosniffandReferrer-Policy: same-origin. An export token in a URL never goes to another site. The pages read the referrer of a same-site navigation. - ChDash refuses every
POST,PUT,PATCHandDELETErequest from a page of another site. It also refuses a body that is notapplication/json. It makes both checks before it reads the body. - A request body has a size limit. A JSON body has a depth limit. The SQL formatter has a depth limit and a time limit.
- The identifiers that act as a capability (
query_id,export_id) are created by the system random source. The signing secret of the tokens and the MCP secrets also come from the system random source. - The log never holds row data, a password, a token or a
query_id. The URIs in the log and in/metricshave no password. - In the authzen mode, ChDash checks the identity token of each request to the pages and to the API. It checks the signature,
iss,aud,expand the life of the token. ChDash checks the action of each route with the PDP. The question names the host and the database of the request, so a grant on one host never covers another host. A PDP error denies the action (fail closed). The log holds each decision (access.decision). It also holds the subject of each request (http.request).
Refer to docs/operations.md for the details. The details cover the headers, the guard, the probes, the shutdown, the log and the metrics.
Each release has the archives, a SHA256SUMS file and a build provenance attestation for each archive. GitHub keeps the attestation, not the release, so a changed archive cannot bring a matching one. The attestation names the workflow run and the commit that built the archive.
sha256sum -c SHA256SUMS --ignore-missing
gh attestation verify chdash_<version>_linux_amd64.tar.gz --repo Circular-fi/Clickhouse-dash --signer-workflow Circular-fi/Clickhouse-dash/.github/workflows/release.yaml --source-ref refs/tags/v<version> --deny-self-hosted-runnersEach option of the command is necessary:
--signer-workflow: With--repoalone, the command also accepts an attestation that another workflow of the repository signed. Only the release workflow builds the archives.--source-ref: The command accepts only an attestation of a run that started from the tag of this version. Without it, the command also accepts an archive that the release workflow built from a branch.--deny-self-hosted-runners: The command accepts only an attestation from a runner that GitHub hosts. The release workflow uses only runners that GitHub hosts.
Manual releases. A maintainer can start the release workflow by hand (Actions > Release > Run workflow). Then the attestation gives the branch of the run as the source ref, not the tag. The page of the workflow run shows this branch. For such a release, give the branch to --source-ref:
gh attestation verify chdash_<version>_linux_amd64.tar.gz --repo Circular-fi/Clickhouse-dash --signer-workflow Circular-fi/Clickhouse-dash/.github/workflows/release.yaml --source-ref refs/heads/main --deny-self-hosted-runnersThe attestation of a manual release also gives the commit of the run. If the tag existed before the run, this commit can be different from the commit of the tag. In this case, the workflow builds the commit of the tag. To compare the two commits, read the log of the job "Resolve release tag".
A release starts only after the tests pass on the commit that it builds. The section "Validate release builds" in CONTRIBUTING.md describes the release chain.
Do not open a public issue for security reports.
Use GitHub private vulnerability reporting when it is enabled for this repository. If it is not available, contact the maintainers through a private channel. Include these items in the report:
- a clear description of the issue
- impact and affected areas
- reproduction steps or proof of concept
- any suggested mitigation
Maintainers will try to acknowledge valid reports quickly. They will assess the severity. They will coordinate a fix before public disclosure.