curl/curl
Security
curl is a security-critical project. It runs untrusted input through dozens of parsers, talks to arbitrary servers, manages credentials and trust roots, and is embedded in billions of devices. The project takes this seriously — there is a published vulnerability disclosure policy, a HackerOne-administered bug bounty, and a long history of CVE handling.
Reporting a vulnerability
Do not open a public GitHub issue or mailing-list message for a suspected security flaw.
- Report at https://curl.se/dev/vuln-disclosure.html
- Or via the bug bounty program (
docs/BUG-BOUNTY.md)
The disclosure policy lives in docs/VULN-DISCLOSURE-POLICY.md. The headline points:
- 90-day standard embargo
- Maintainer-coordinated disclosure with CNA assignment via curl's CNA scope
- Reports triaged within 24 hours by the security team
- Advisories published with patches at https://curl.se/docs/security.html
Trust boundaries
| Boundary | What is on each side |
|---|---|
| Application ↔ libcurl | Application sets options, libcurl receives bytes from arbitrary servers |
| libcurl ↔ network peer | Server-controlled bytes flow through every parser in lib/ |
| libcurl ↔ proxy | Even authenticated proxies can inject arbitrary headers |
| libcurl ↔ TLS backend | Backend has its own attack surface; curl validates certificates and pins keys |
| libcurl ↔ resolver | DNS responses (or DoH responses) can be untrusted |
| Application user ↔ filesystem | Cookie jar, HSTS file, alt-svc file, .netrc are written and read |
The defaults assume the network is hostile, the server is untrusted, and the resolver may be lying.
Defensive practices in the codebase
- Memory tracking:
lib/memdebug.cwraps every allocation in debug builds; the test suite injects allocation failures via torture mode (tests/runtests.pl -t) to exercise error paths. - Fuzzing: OSS-Fuzz has run libcurl since July 2017. Harnesses are under
tests/fuzz/. - CI sanitizers: AddressSanitizer, UndefinedBehaviorSanitizer, MemorySanitizer in
.github/workflows/linux.yml. CodeQL in.github/workflows/codeql.yml. - Strict format checks:
mprintf.cis curl's own printf implementation that handles 64-bit args portably and is checked byscripts/checksrc.pl. - Bounded parsing:
lib/curlx/strparse.cis the project's non-allocating tokeniser; new parsers should use it rather than ad-hoc loops. - Style enforcement:
scripts/checksrc.plblocks risky idioms (e.g.strcpy,strcat, unbounded format strings). - Public Suffix List: cookies are scoped via libpsl in
lib/psl.cto prevent setting a cookie for.comor.co.uk. .onionrefusal: curl refuses to resolve.onionhostnames by default to avoid DNS leak (since May 2023). Override viaCURLOPT_DOH_URLor routing through a SOCKS proxy.- HSTS: persisted between runs via
CURLOPT_HSTS.
TLS-related considerations
- Multiple TLS backends mean multiple sets of trust-root quirks. See TLS backends.
- The Mozilla CA bundle generator
scripts/mk-ca-bundle.plproduces a curl-friendly PEM file fromcertdata.txt. - Pinning is supported via
CURLOPT_PINNEDPUBLICKEYand--pinnedpubkeyand is back-end agnostic. - Cipher suite naming is portable across backends via
lib/vtls/cipher_suite.c. - TLS session tickets are cached in
lib/vtls/vtls_scache.cand shareable via the share interface.
Authentication considerations
- Credentials may come from
CURLOPT_USERPWD,~/.netrc, or per-protocol options. They are never logged in trace output (the trace output redacts headers). - The connection cache does use credential-affecting options as part of the connection key — two requests with different users do not share a connection.
- NTLM and Negotiate are connection-bound: a connection authenticated as user A is not reused for user B.
Specific risks called out in the docs
docs/KNOWN_RISKS.md enumerates accepted risks (truncated list):
- HTTP redirect to FILE/SCP/SFTP can leak local data (mitigated by
CURLOPT_REDIR_PROTOCOLS_STR). - TLS handshake error messages may leak internal state.
- Long-running connections can outlive their security context.
- Reading
.netrcis line-based; do not store anything but credentials there.
CVE history
curl publishes detailed advisories at https://curl.se/docs/security.html. The release-notes file RELEASE-NOTES includes a security-fix bullet for every advisory shipped with that release. The repo also keeps .git-blame-ignore-revs to keep git blame accurate across mass formatting changes — an indirect aid to security review.
Threat model for new code
When adding code that touches the network, ask:
- What is the attacker-controlled input? Headers, body bytes, DNS responses, certificate fields, redirect URLs.
- Where is the trust boundary? Usually before the first allocation or string copy.
- Is there a length cap? If you are reading until a delimiter, the cap is on the total amount of bytes you are willing to allocate.
- Is the result being mixed with subsequent unauthenticated bytes? If yes, ensure invariants for the next layer.
- Is there a similar parser elsewhere? Reuse
lib/curlx/strparse.candlib/dynhds.crather than rolling a new tokenizer.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.