Back to Articles

Cert Spotter: Building a Certificate Transparency Monitor Without a Database

[ View on GitHub ]

Cert Spotter: Building a Certificate Transparency Monitor Without a Database

Hook

A certificate with a null byte in its domain name could fool most monitoring systems into thinking it’s legitimate. Cert Spotter treats it as an attack and alerts both affected parties.

Context

Certificate Transparency (CT) logs are append-only ledgers where every TLS certificate issued by a trusted Certificate Authority must be recorded. This creates a permanent, public record that makes it impossible for CAs to issue certificates in secret. If an attacker tricks a CA into issuing a certificate for your domain, that certificate will appear in CT logs—giving you a chance to detect and respond to the compromise before browsers trust it.

The problem is that CT logs collectively record millions of certificates per day across dozens of different log servers maintained by Google, Cloudflare, DigiCert, and others. Monitoring these logs requires continuously downloading entries, parsing X.509 certificates (a notoriously complex format), matching them against your domains, and alerting when something suspicious appears. Most existing solutions require PostgreSQL or similar databases, complex deployment pipelines, and trust that their certificate parsers handle every edge case correctly. Cert Spotter takes a different approach: stateless operation, defensive parsing, and an adversarial threat model that assumes attackers will exploit parsing differences.

Technical Insight

Fetch certificate entries

Raw certificates

Certificate data

Track position

Match found

Email alert

Execute

Verify integrity

Watchlist File

DNS names to monitor

CT Log APIs

RFC6962 & static-ct-api

CT Log Scanner

Stateless fetcher

Defensive Parser

ASN.1 byte search

Domain Matcher

Scan entire cert structure

State Directory

Log offset pointers

Notification System

Sendmail

Custom Hook Script

Log Auditor

Append-only check

System architecture — auto-generated

Cert Spotter’s architecture revolves around a single design principle: avoid making assumptions about certificate structure that could create blind spots. Traditional CT monitors parse certificates using standard X.509 libraries, extract the Common Name and Subject Alternative Names, then check if they match watchlist entries. This approach has a critical flaw—if a certificate is malformed in a way that causes parsing to fail or return unexpected results, the monitor might miss it entirely while browsers (with different parsers) still accept it.

The tool implements defensive parsing by keeping certificates mostly unparsed and operating on raw ASN.1 structures. When scanning for domain names, it doesn’t just look in the expected fields; it searches through the entire certificate for byte sequences that might represent identifiers. This catches certificates with malformed extensions, incorrectly encoded fields, or deliberately crafted structures designed to appear different to different parsers. Here’s how you’d run a basic monitoring session:

# Create a watchlist file with domains to monitor
echo 'example.com' > watchlist.txt
echo '*.example.com' >> watchlist.txt

# Run Cert Spotter as a daemon
certspotter -watchlist watchlist.txt \
  -state_dir /var/lib/certspotter \
  -script /usr/local/bin/alert-handler.sh

The state directory contains one file per CT log with a simple offset pointer—no database, no schema migrations, no query optimization. When Cert Spotter finds a matching certificate, it invokes the script with environment variables containing parsed data:

#!/bin/bash
# alert-handler.sh example

echo "Certificate discovered for ${DNS_NAMES}" 
 echo "Issuer: ${CERT_ISSUER}"
echo "Serial: ${CERT_SERIAL}"
echo "Log: ${LOG_URI}"
echo "Fingerprint: ${CERT_FINGERPRINT}"

# Send to your monitoring system
curl -X POST https://alerts.example.com/webhook \
  -d "domain=${DNS_NAMES}" \
  -d "fingerprint=${CERT_FINGERPRINT}"

The null-byte handling demonstrates the adversarial mindset. RFC 5280 technically prohibits null bytes in DNS names, but what happens if a CA mistakenly issues a certificate for example.org\0.attacker.com? Some parsers might stop at the null byte and see example.org, while others might skip to after the null and see .attacker.com. Cert Spotter treats this as an attack attempt and generates alerts for both example.org and attacker.com, ensuring both domain owners get notified regardless of how their infrastructure parses the certificate.

Cert Spotter monitors both legacy RFC 6962 logs (which provide real-time access via HTTP APIs) and modern static-ct-api logs that Google and Apple now require. Static logs are served as flat files optimized for CDN caching, reducing server costs for log operators while maintaining transparency. The tool automatically detects which protocol each log uses and adapts its fetching strategy:

// Simplified architecture of log monitoring
for _, logInfo := range logs {
    state := loadState(logInfo.URL)
    
    if logInfo.IsStaticCTAPI {
        // Fetch tile-based static logs
        entries := fetchStaticTiles(logInfo, state.Position)
    } else {
        // Fetch from RFC 6962 get-entries endpoint
        entries := fetchRFC6962Entries(logInfo, state.Position)
    }
    
    for _, entry := range entries {
        identifiers := extractIdentifiers(entry.Certificate)
        if matchesWatchlist(identifiers, watchlist) {
            notify(entry)
        }
    }
    
    saveState(logInfo.URL, newPosition)
}

Beyond monitoring, Cert Spotter includes auditing capabilities that verify logs maintain their append-only property. The tool stores Merkle tree hashes and checks that historical entries never change—a critical security property that prevents log operators from rewriting history. If a log violates this property (either through malicious action or software bugs), Cert Spotter detects it immediately. This positions the tool as both a monitoring solution and a participant in the broader CT ecosystem’s security model.

Gotcha

The stateless design that makes Cert Spotter easy to deploy also creates operational challenges. When you first start monitoring, you face a choice: start from the beginning of each log (potentially gigabytes of data representing years of certificates) or use -start_at_end to only catch new certificates going forward. The former consumes significant bandwidth and time, while the latter means you miss any certificates issued before you started watching. There’s no incremental backfill option—you can’t say “give me the last 30 days” without processing everything or nothing.

Email notifications rely on the sendmail command being present and correctly configured on your system. In containerized or cloud-native environments, this is rarely the case by default. You’ll need to either install and configure a mail transfer agent (postfix, exim, etc.) or implement all notification logic in the hook script. The hook script approach works well but means you’re responsible for retry logic, rate limiting, and delivery guarantees that email systems typically provide. If your script crashes or your webhook endpoint is down, that alert is lost forever unless you implement your own queuing.

The lack of a built-in web dashboard means all certificate history lives in log files or wherever your hook script sends it. Want to review all certificates discovered for a domain last month? You’ll need to build that yourself by parsing logs or storing hook script output in a database—ironically recreating the database complexity Cert Spotter avoids. The commercial SSLMate Cert Spotter service provides this UI, but the open-source version is strictly command-line focused. For organizations that need compliance reporting or executive visibility, this creates extra engineering work.

Verdict

Use if you’re building security infrastructure where you need complete control over certificate monitoring, can handle script-based notifications, and value the adversarial threat model that catches malformed certificates other monitors miss. It’s ideal for security teams at companies that already have alerting infrastructure (PagerDuty, Slack, custom webhooks) and want CT monitoring to integrate into existing workflows without adding database dependencies. The defensive parsing approach makes this the right choice if you’re genuinely worried about sophisticated attackers exploiting parser differences. Skip if you need a turnkey solution with a web dashboard, want built-in notification channels beyond email, or don’t have the operational expertise to run and monitor a daemon. Also skip if you’re monitoring hundreds of domains and need historical search, certificate analytics, or expiration tracking—those features require either building significant tooling around Cert Spotter or using the commercial hosted service. For individual developers or small teams wanting basic CT monitoring, crt.sh’s web interface or the hosted SSLMate service will be less work.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/sslmate-certspotter.svg)](https://starlog.is/api/badge-click/cybersecurity/sslmate-certspotter)