Open-Source Wikis

/

CoreDNS

/

Security

coredns/coredns

Security

This page documents the security model of the CoreDNS codebase. The user-facing security tooling — the plugins themselves — is described in Plugins → Security.

Trust boundaries

CoreDNS runs as a network-facing process. The concentric trust boundaries are:

graph TD
    Untrusted[Untrusted DNS clients]
    Untrusted -->|UDP/TCP DNS, DoT, DoH, DoH3, DoQ, gRPC| Listeners[core/dnsserver listeners]
    Listeners --> Limits[connection limits, TLS termination]
    Limits --> Server[Server.ServeDNS]
    Server --> Chain[plugin chain]
    Chain --> Backends[plugin/file, kubernetes, etcd, ...]
    Backends --> External[upstream DNS, Kubernetes API, cloud DNS APIs]

The most sensitive boundary is the listener: a malformed or oversized DNS message is the first thing a remote attacker can send. The second is upstream services — a compromised etcd or Kubernetes API server has read/write access to served data.

Server-side defences

core/dnsserver/server.go implements several first-line defences before the plugin chain runs:

  • Question-section validation. Empty question sections are rejected with SERVFAIL.
  • recover() on plugin panics. Unless the debug plugin disables it. A panic does not crash the process; vars.Panic is incremented and SERVFAIL is returned.
  • Class filtering. Non-INET (CH, HS, ANY) class queries are refused unless one of chaos, forward, or proxy is loaded. This blocks a class of zone-walking and amplification attacks.
  • EDNS0 version check. Wrong versions get a BADVERS reply instead of being parsed further.
  • ScrubWriter. Replies are truncated to the client's advertised buffer size, defending against UDP fragmentation attacks.
  • Connection limits. ServerHTTPS, ServerHTTPS3, ServerQUIC, and ServergRPC cap concurrent connections (default 200) and streams (default 256). Plain UDP is rate-limited externally if needed.

Encrypted transports

tls, https, https3, quic, grpc_server plugins set up encrypted listeners. The tls plugin uses plugin/pkg/tls to assemble a *tls.Config. The default Go TLS settings are used; CoreDNS does not pin cipher suites except where the underlying library does (e.g. QUIC requires AES-GCM or ChaCha20-Poly1305).

For DoT, DoH, DoH3, and DoQ, TLS is required — not setting tls is a setup error. Plain dns:// does not encrypt; acl and tsig are the in-band defences.

Authentication

CoreDNS is mostly an unauthenticated server. Two exceptions:

  • TSIG (plugin/tsig). HMAC-signed DNS messages are verified against a per-server TsigSecret map. Used most often to authenticate AXFR.
  • Per-RPC authentication for upstream APIs (Kubernetes, etcd, cloud providers) lives in the corresponding backend plugins. Credentials come from kubeconfigs, IAM roles, environment variables, or files referenced from the Corefile.

Authorization is implemented via acl (CIDR-based, qtype-based) and view (expression-based). Together they cover most "tenant separation" needs.

Secret handling

  • TSIG keys are stored in the Caddyfile or referenced by file path.
  • DNSSEC private keys for the dnssec plugin: read from local files (key file) or AWS Secrets Manager (key aws_secretsmanager). Keys never leave the process; signatures are computed in-memory.
  • Cloud credentials for route53, azure, clouddns, nomad, secretsmanager: come from the SDK's default credential chain. Embedding credentials in the Corefile is supported but discouraged — prefer IAM roles, instance metadata, or workload identity.

There is no built-in support for HashiCorp Vault. Plugins that need secrets read them from disk or environment.

Known attack surface

  • DNS amplification. Mitigated by any (RFC 8482), minimal, and cache (which decouples upstream load from query load). Operators should still rate-limit at the network edge.
  • UDP source spoofing. Inherent to DNS over UDP. The standard mitigations apply: BCP 38 ingress filtering at the network, acl plugin for tenant restrictions.
  • Plugin panics. A bug in a plugin can panic the goroutine handling a request. The recover() in Server.ServeDNS keeps the process up.
  • Zone-walking. The dnssec plugin uses NSEC black lies (synthesised tight-range NSEC records) so an attacker can't enumerate the zone via DNSSEC denials.
  • Fragmentation-based poisoning. bufsize clamps client-advertised buffer sizes to a fragmentation-safe value.
  • Loop forwarding. The loop plugin probes at startup and refuses to start if a forwarding loop exists.

Dependency hygiene

  • Dependabot opens daily PRs for gomod, github-actions, and Docker base images.
  • coredns-auto-go-mod-tidy[bot] runs go mod tidy after Dependabot mass updates.
  • GitHub CodeQL (.github/workflows/codeql-analysis.yml) runs static analysis on every PR.
  • gosec (configured in .golangci.yml) catches common security issues during lint.
  • OSS-Fuzz (.github/workflows/cifuzz.yml) runs fuzz harnesses on every PR.
  • Trivy (.github/workflows/trivy-scan.yaml) scans container images.
  • OpenSSF Scorecard (.github/workflows/scorecards.yml) tracks supply-chain hygiene.

The repo also publishes a CII Best Practices badge and an OpenSSF Scorecard badge.

Audits

The CoreDNS README links to two third-party security reviews:

Reporting vulnerabilities

Do not open a public issue. Email security@coredns.io. The full process is in .github/SECURITY.md. Highlights:

  • Initial response within a small number of days.
  • A Product Security Team coordinates fix and disclosure.
  • Distributors on coredns-distributors-announce@lists.cncf.io may receive embargoed pre-release information.
  • A CVE is requested for each vulnerability.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Security – CoreDNS wiki | Factory