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 thedebugplugin disables it. A panic does not crash the process;vars.Panicis incremented and SERVFAIL is returned.- Class filtering. Non-INET (CH, HS, ANY) class queries are refused unless one of
chaos,forward, orproxyis 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, andServergRPCcap 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-serverTsigSecretmap. 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
dnssecplugin: 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, andcache(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,
aclplugin for tenant restrictions. - Plugin panics. A bug in a plugin can panic the goroutine handling a request. The
recover()inServer.ServeDNSkeeps the process up. - Zone-walking. The
dnssecplugin uses NSEC black lies (synthesised tight-range NSEC records) so an attacker can't enumerate the zone via DNSSEC denials. - Fragmentation-based poisoning.
bufsizeclamps client-advertised buffer sizes to a fragmentation-safe value. - Loop forwarding. The
loopplugin 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]runsgo mod tidyafter 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:
- Cure53 audit — March 2018.
- Trail of Bits review — March 2022.
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.iomay 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.