Introduction

Attack surface drift detection exists because your external exposure does not stay still. A domain that was clean last week may have a new subdomain today. A deploy may remove a security header. A certificate may cross into its expiry window. A DNS record may weaken email authentication.

The Capital One incident is a useful reminder that serious exposure can come from configuration weakness, not only from a new asset or newly published CVE. Capital One publicly described the 2019 breach as involving a configuration vulnerability and said the issue was reported through its Responsible Disclosure Program on July 17, 2019, with discovery on July 19.

That is the threat model drift detection addresses: not only unknown assets, but known assets whose security posture changes between one review and the next.

This guide explains the main categories of attack surface drift, how to create a usable baseline, how to monitor change safely, and how to separate expected changes from real security regressions.

What you need before you start

You need at least one external scan of the domains and assets you are authorized to assess. A useful starting scan should include subdomains, DNS records, HTTP services, TLS posture, security headers, exposed ports, and known third-party service relationships.

You also need somewhere to store results. Drift detection depends on comparison. If yesterday's scan output is not saved in a stable format, today's scan has nothing reliable to compare against.

The command examples below use common tools such as subfinder, dnsx, httpx, nmap, dig, jq, and openssl. Run them only against domains, IPs, and networks you own or have explicit authorization to test.

The examples use GNU/Linux date syntax such as date -d. On macOS or BSD systems, adjust date commands or use a small script in Python instead.

Step 1: understand attack surface drift detection categories

Drift is not one event type. Different changes move at different speeds and need different monitoring logic.

Treating every change the same creates either alert fatigue or missed exposure. A new internet-facing service is not the same as a certificate renewal, and a new OAuth grant is not the same as a closed port.

  • Asset inventory drift — Asset inventory drift happens when assets appear or disappear. Examples include a new subdomain, a new IP attached to a public service, a new cloud storage endpoint, a removed subdomain, or a port that is no longer reachable. This type of drift answers the question: what exists today that did not exist before?

  • Configuration drift — Configuration drift happens when an existing asset changes posture. Examples include a missing Content-Security-Policy header, a DMARC policy weakened from p=reject to p=none, a new open port on an existing host, a certificate approaching expiry, a TLS configuration regression, or a cloud access policy becoming public.

  • Relationship drift — Relationship drift happens when your organization gains a new external dependency or trust relationship. Examples include a new CNAME pointing to a third-party service, a new OAuth app connected to a workspace, a new SaaS integration, a new vendor-managed subdomain, or an API key exposed through a public JavaScript bundle.

Step 2: establish a valid baseline

A baseline is a reviewed state, not just the first scan output. The first scan is useful, but it often contains old findings, unknown assets, false positives, and issues nobody has triaged yet.

A practical baseline requires review. For each important finding, decide whether it should be fixed, accepted with justification, assigned to an owner, or tracked as needing validation.

Run more than one scan before locking the baseline. Passive discovery sources can vary because APIs change, rate limits apply, source coverage shifts, or API keys differ between runs. Keep scanner versions, source configuration, API keys, and wordlists stable while building the baseline.

A baseline should be timestamped and re-reviewed after major infrastructure changes such as acquisitions, cloud migrations, DNS provider changes, major product launches, or domain portfolio changes.

  • Build a stable subdomain baseline — Run the same approved discovery pipeline twice and compare results. Differences may reflect real drift or passive-source variability, so review the diff before accepting the baseline.

    # Day 1
    subfinder -d example.com -silent | dnsx -silent -a -resp | sort > scan_day1.txt
    
    # Day 2, same tool versions and source config
    subfinder -d example.com -silent | dnsx -silent -a -resp | sort > scan_day2.txt
    
    # Compare
    diff scan_day1.txt scan_day2.txt
    
    # Expected output for a stable baseline:
    # no diff output, or only reviewed differences explained by source variance
  • Record baseline decisions — A baseline should preserve what was reviewed and why it was accepted. This prevents old unresolved issues from hiding future drift.

    # Example baseline review fields
    asset: api.example.com
    finding: missing Content-Security-Policy
    status: accepted temporarily
    owner: web-platform
    reviewed_at: 2026-05-09
    reason: legacy app migration scheduled
    review_again: 2026-06-09

Step 3: detect asset inventory drift

Asset inventory drift is usually the easiest place to start. The question is simple: which domains, hosts, ports, or services are new, and which disappeared?

The safest approach is to run the same scan against an approved scope, save sorted output, and diff it against the previous run.

  • Subdomain diff pipeline — Run discovery on a schedule and compare against the previous output. New lines are newly observed subdomains. Removed lines are no longer observed by this pipeline.

    #!/bin/bash
    set -euo pipefail
    
    DOMAIN="example.com"
    DATE=$(date +%Y-%m-%d)
    PREV_DATE=$(date -d 'yesterday' +%Y-%m-%d)
    OUTDIR="/opt/drift-monitoring/$DOMAIN"
    mkdir -p "$OUTDIR"
    
    subfinder -d "$DOMAIN" -silent | dnsx -silent -a -resp | sort > "$OUTDIR/$DATE.txt"
    
    if [ -f "$OUTDIR/$PREV_DATE.txt" ]; then
      comm -13 "$OUTDIR/$PREV_DATE.txt" "$OUTDIR/$DATE.txt" > "$OUTDIR/new-$DATE.txt"
      comm -23 "$OUTDIR/$PREV_DATE.txt" "$OUTDIR/$DATE.txt" > "$OUTDIR/removed-$DATE.txt"
    fi
    
    # Expected output:
    # new-YYYY-MM-DD.txt contains newly observed records.
    # removed-YYYY-MM-DD.txt contains records no longer observed.
  • Port drift on approved hosts — Do not scan broad ranges by default. Start with an approved host list, scan the ports that matter to your environment, and diff the output.

    # approved_hosts.txt contains only hosts or IPs you own and are authorized to test.
    
    nmap -p 22,80,443,8080,8443,3306,5432,6379,9200,27017,3389 \
      --open -iL approved_hosts.txt -oG ports_today.gnmap
    
    # Normalize output for comparison
    grep 'Ports:' ports_today.gnmap | sort > ports_today.txt
    
    diff ports_yesterday.txt ports_today.txt | grep '^[<>]' || true
    
    # Expected output:
    # Lines beginning with > are newly observed open ports.
    # Lines beginning with < were present before but not observed today.

Step 4: detect configuration drift

Configuration drift is harder than asset drift because the asset may look normal at first glance. The hostname still resolves. The application still returns 200. But a security control may have changed.

For most external attack surfaces, the highest-value checks are security headers, DMARC policy, TLS certificate expiry, TLS configuration, DNS records, exposed ports, and cloud exposure signals.

  • Security header regression — Store selected response headers for known web assets and compare them between runs. A header that existed yesterday and disappeared today should be reviewed.

    # Scan current headers
    cat known_web_assets.txt | httpx -silent \
      -H 'User-Agent: SecurityAudit/1.0' \
      -include-response-header \
      -json -o headers_today.json
    
    # Extract security-relevant headers
    cat headers_today.json | jq -r '[.url,
      .header["content-security-policy"],
      .header["x-frame-options"],
      .header["strict-transport-security"],
      .header["x-content-type-options"]] | @csv' | sort > security_headers_today.csv
    
    # Compare
    diff security_headers_yesterday.csv security_headers_today.csv || true
    
    # Expected output:
    # no diff means no observed header drift.
    # removed CSP, HSTS, X-Frame-Options, or X-Content-Type-Options values need review.
  • DMARC policy drift — A DMARC policy weakened from reject or quarantine to none is a meaningful regression. Track the policy value and alert only when it changes.

    DOMAIN="example.com"
    DMARC=$(dig TXT "_dmarc.$DOMAIN" +short | tr -d '"' | grep -oE 'p=(none|quarantine|reject)' | head -1)
    DATE=$(date +%Y-%m-%d)
    
    echo "$DATE $DMARC" >> dmarc_history.txt
    
    tail -2 dmarc_history.txt > dmarc_last_two.txt
    
    # Expected output:
    # 2026-05-08 p=reject
    # 2026-05-09 p=reject
    # If the second line differs, review the change.
  • TLS certificate expiry drift — Certificate expiry is predictable drift. Alert when a certificate crosses a threshold, not every time the day count changes.

    HOST="example.com"
    EXPIRY=$(echo | openssl s_client -servername "$HOST" -connect "$HOST:443" 2>/dev/null | \
      openssl x509 -noout -enddate | cut -d= -f2)
    
    EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
    NOW_EPOCH=$(date +%s)
    DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
    
    echo "$(date +%Y-%m-%d) $HOST $DAYS_LEFT" >> cert_expiry_history.txt
    
    if [ "$DAYS_LEFT" -lt 30 ]; then
      echo "Review certificate: $HOST expires in $DAYS_LEFT days"
    fi
    
    # Expected output:
    # Review only when the certificate crosses your threshold, such as 30, 14, or 7 days.
  • AWS metadata hardening drift — For AWS workloads, include metadata-service hardening checks where possible. Requiring IMDSv2 reduces risk from SSRF paths that attempt to retrieve instance metadata credentials.

    # Example: list EC2 instances and metadata options
    aws ec2 describe-instances \
      --query 'Reservations[].Instances[].{InstanceId:InstanceId,HttpTokens:MetadataOptions.HttpTokens,HttpEndpoint:MetadataOptions.HttpEndpoint}' \
      --output table
    
    # Expected secure posture for many workloads:
    # HttpTokens = required
    # HttpEndpoint = enabled only when the instance needs metadata access

Step 5: choose the right monitoring cadence

Cadence should match asset criticality, deployment frequency, and response capacity. More frequent scanning is not automatically better if nobody can triage the alerts.

High-change teams may need more frequent CT log, subdomain, and service monitoring than low-change teams. For many teams, daily external checks plus deployment-triggered checks are more realistic than hourly full-surface scans.

Slow-moving checks should not page people every time they change. A certificate renewal, CDN IP change, or planned vendor CNAME may be expected drift. The job is to identify unexpected or risky drift.

  • Deployment-triggered checks — Run a focused drift check after deployments that change DNS, cloud resources, CDN configuration, web headers, or public services.

    # Example post-deploy checks
    # 1. Resolve new or changed hostnames.
    # 2. Check HTTP headers on changed web apps.
    # 3. Check open ports on changed hosts.
    # 4. Check TLS certificate state.
    # 5. Compare against expected changes from the deployment ticket.
    
    # Expected output:
    # only changes associated with the approved deployment should appear.
  • Daily checks — Daily checks are a practical default for many teams. They work well for subdomain discovery, port drift, header drift, DMARC changes, CAA changes, and certificate expiry thresholds.

    # Daily cron example
    # 0 7 * * * /opt/drift-monitoring/run-external-checks.sh
    
    # Expected output:
    # A daily change summary with new assets, removed assets,
    # risky configuration changes, and certificate threshold crossings.
  • Weekly relationship review — Relationship drift often needs human review. New CNAME records, OAuth grants, SaaS apps, and vendor integrations should be reviewed on a slower cadence unless they affect critical production paths.

    # Weekly DNS relationship review for owned zones
    # Prefer DNS provider export or API where possible.
    
    dig axfr example.com @authorized-ns.example.com | grep CNAME | sort > cname_this_week.txt
    
    diff cname_last_week.txt cname_this_week.txt || true
    
    # Expected output:
    # new CNAMEs should map to approved vendors or planned services.
    # unknown third-party targets need owner review.

Step 6: suppress expected drift without hiding real risk

A drift program that alerts on every change quickly becomes noise. The goal is not to alert on all drift. The goal is to alert on unexpected or risky drift.

Expected drift should be tied to a change record, deployment, owner, and expiry date. If an allowlist entry never expires, it becomes a second shadow baseline.

Severity tiering also matters. A new subdomain pointing to an approved CDN may be informational. A new subdomain pointing to an unknown IP with SSH open needs faster review.

  • Expected-change allowlist — Maintain an allowlist for planned changes. Remove entries after they are merged into the reviewed baseline.

    # expected_changes.txt
    # format: value | owner | expiry | reason
    new-feature.example.com | web-platform | 2026-05-15 | product launch
    api-v2.example.com | api-team | 2026-05-15 | migration
    
    # Filter new assets against expected values
    awk -F'|' '{print $1}' expected_changes.txt | sed 's/[[:space:]]*$//' > expected_values.txt
    
    grep -vFf expected_values.txt new-assets-today.txt > unexpected_new_assets.txt
    
    # Expected output:
    # unexpected_new_assets.txt should contain only changes not tied to a planned deployment.
  • Severity rules for drift — Prioritize drift by risk, not by novelty alone.

    # Example severity rules
    # High: new public admin panel, new database port, DMARC reject -> none,
    #       new subdomain takeover candidate, public cloud storage exposure
    # Medium: new vendor CNAME, missing CSP on non-critical app,
    #         certificate below 30 days
    # Low: expected CDN IP change, planned subdomain, certificate renewal
    
    # Expected output:
    # alerts are routed by severity instead of producing one flat diff list.

Common mistakes in drift detection programs

Several patterns reduce the value of drift monitoring even when scans run successfully.

  • Using the first scan as a silent baseline — The first scan may contain unresolved findings and unknown assets. Review it before treating it as normal.

  • Ignoring scanner-source drift — Passive tools can produce different output when source coverage, API keys, rate limits, or versions change. Keep tool configuration stable when comparing runs.

  • Alerting on every change — Certificate renewals, planned subdomains, and expected vendor records should not generate the same alert severity as a new public database port.

  • Scanning slower than your change rate — If public services change daily but scans run monthly, drift detection becomes incident archaeology instead of operational monitoring.

  • Monitoring only the apex domain — Most drift appears on subdomains, third-party CNAMEs, cloud endpoints, and public services, not on the apex domain itself.

  • Never refreshing the baseline — A six-month-old baseline often contains legitimate changes that should be reviewed and incorporated. Stale baselines create false positives and reduce trust.

How to automate drift detection continuously

Manual scripts are a good starting point because they teach the team what changed and why it matters. The operational cost appears later: jobs fail, passive sources change, output formats shift, and alerts need triage.

A mature drift workflow stores historical scan results, compares current state with prior state, labels expected changes, and routes risky changes to the right owner.

For the external surface, an EASM platform can reduce the maintenance burden by handling discovery, scanning, historical comparison, alerting, and reporting in one workflow.

The value is not only automation. The value is reducing the time between a risky change being introduced and someone noticing it.

Where ExternalSight fits

ExternalSight fits the external attack surface layer for internet-facing domains. It is not an internal vulnerability scanner, SIEM, EDR, or cloud posture platform.

ExternalSight supports on-demand asynchronous scans, continuous monitoring for verified domains on supported plans, historical comparison, alerting, issue classification, remediation planning, PDF export, JSON export on supported plans, and plan-gated notifications.

Its scanner coverage includes areas relevant to drift detection, such as DNS, certificate transparency, subdomains, TLS, HTTP headers, subdomain takeover, ports, cloud exposure, email spoofing, zone transfer, admin panels, exposed services, passive DNS, OTX intelligence, and attack-chain evaluation.

Scanner coverage is tracked when a module, API key, or external source is unavailable, so reports can preserve partial results instead of pretending every check succeeded.

Final verdict

Attack surface drift detection is the difference between knowing what was exposed once and knowing what changed since then.

Asset drift tells you what appeared or disappeared. Configuration drift tells you what became weaker or stronger. Relationship drift tells you which third-party dependencies or trust paths changed.

The hard part is not running one scan. The hard part is maintaining a reviewed baseline, keeping scan inputs stable, suppressing expected changes, and escalating risky differences quickly.

A good drift program does not re-report everything. It tells you what changed, why it matters, who owns it, and whether the change was expected.

Key takeaways

  • Attack surface drift detection compares current external exposure against a reviewed prior state.
  • There are three main drift categories: asset inventory drift, configuration drift, and relationship drift.
  • The first scan should be reviewed before it becomes a baseline. Otherwise, old unresolved issues become normalized.
  • Passive discovery results can drift because tools, sources, API keys, and rate limits change. Keep scan inputs stable when comparing runs.
  • Monitoring cadence should match risk and response capacity. Daily checks plus deployment-triggered checks are more realistic for many teams than hourly full-surface scans.
  • ExternalSight supports historical comparison and alerting for verified domains on supported plans, with coverage-aware reporting when checks are unavailable.

Frequently asked questions

What is attack surface drift detection?
Attack surface drift detection is the process of comparing your current external exposure against a reviewed previous state to identify new assets, removed assets, configuration regressions, and changed third-party relationships.
How is drift detection different from vulnerability scanning?
Traditional CVE scanning checks known vulnerabilities against known assets. Drift detection checks what changed: new subdomains, new ports, missing headers, DNS policy changes, certificate expiry thresholds, new CNAMEs, and other exposure changes that may not have a CVE.
How often should I run drift detection?
Use a cadence that matches your risk and change rate. Many teams start with daily external checks and deployment-triggered checks for high-risk changes. High-change environments may need more frequent monitoring for critical domains or production services.
How long should I retain scan history?
Keep at least 30 days for operational drift comparison. Longer retention, such as 12 months, is useful for audits, incident investigation, and answering when a configuration changed.
Can drift detection catch insider threats?
It can catch externally visible changes regardless of who made them, such as a weakened DMARC record, a new public service, or a new DNS record. It will not catch internal activity that does not change the external surface; that requires SIEM, EDR, identity monitoring, and internal controls.
Does ExternalSight replace vulnerability scanning?
No. ExternalSight helps monitor external attack surface exposure for internet-facing domains. It complements internal vulnerability scanning, EDR, SIEM, CSPM, and identity monitoring rather than replacing them.

Track external exposure changes

ExternalSight helps teams scan internet-facing domains and monitor verified domains for external exposure changes. It supports historical comparison, alerting, issue classification, remediation planning, PDF/JSON export, and coverage-aware reporting when scanners or external sources are unavailable.