Attack Surface Management for Web Applications: Discovery, Monitoring, and Reduction
Most organizations have a security scanning program. They scan the production domain. They test the login page and the checkout flow. They run a DAST scan before major releases. And then they get breached through a forgotten staging environment that hasn't been patched since 2023, or a shadow API endpoint left over from a deprecated mobile app, or an S3 bucket spun up by a developer who left the company eighteen months ago.
This is the attack surface problem. The vulnerabilities you scan for are less dangerous than the assets you forgot you had. Attack Surface Management (ASM) is the discipline of finding, cataloging, and continuously monitoring everything that could be an entry point — before attackers find it first.
This guide covers the full ASM methodology for web applications: the five attack surface layers, the discovery tools and techniques professionals use, how to detect shadow IT and orphaned endpoints, how to build continuous monitoring, and how to integrate ASM into a DevSecOps pipeline that actually keeps pace with a fast-moving engineering team.
What Attack Surface Management Actually Is
ASM is not vulnerability scanning. Vulnerability scanning assumes you already know what you're scanning — you provide a target, and the scanner tests it. ASM is the step before that: discovering what targets exist in the first place.
The distinction matters enormously in practice. A scanner running against app.example.com will test everything on that domain. It will not find api-v2-staging.example.com, which is also exposed to the internet, running an older version of your application stack, and accessible with credentials that were rotated on production but not on staging. An ASM program would find that subdomain, enumerate its services, and feed it into the scanning pipeline automatically.
ASM has three phases that run continuously, not once:
- Discovery — finding all internet-exposed assets associated with your organization: domains, subdomains, IP ranges, cloud storage, APIs, and services you may not know about
- Inventory — cataloging what was found, classifying it by type and risk level, and tracking ownership
- Monitoring — detecting changes to the attack surface over time: new assets appearing, existing assets changing, or previously seen assets going dark (which may indicate subdomain takeover opportunity)
Vulnerability scanning feeds off the output of ASM. You can't test what you haven't discovered.
The Five Attack Surface Layers
For web applications, the attack surface organizes into five distinct layers, each requiring different discovery techniques and each carrying different risk profiles.
Layer 1: Network Exposure
The IP addresses and port/service combinations your organization exposes to the internet. This includes web servers (80, 443), but also administrative interfaces (SSH on 22, RDP on 3389), database ports accidentally exposed (3306, 5432, 27017), development servers (8080, 8443, 3000, 4000), and monitoring tools (Grafana on 3000, Kibana on 5601, Jenkins on 8080). Each of these is a potential entry point. Many organizations are shocked to learn what's listening on public IPs assigned to their cloud accounts.
Layer 2: Subdomains and DNS
The most commonly overlooked layer. Large organizations accumulate hundreds of subdomains over years of development, acquisitions, marketing campaigns, and infrastructure changes. Many of these point to services that were decommissioned without cleaning up DNS records — creating subdomain takeover opportunities. Others point to development and staging environments with weaker security controls than production.
Layer 3: Web Applications
The actual application surface: pages, endpoints, forms, file upload handlers, redirects, and embedded third-party content. This is what traditional DAST scanners cover — but only for the targets you give them. ASM ensures the DAST scope is complete.
Layer 4: APIs
REST APIs, GraphQL endpoints, WebSocket services, and gRPC interfaces. APIs are particularly dangerous attack surface because they're often developed and deployed independently of the main application, may have their own authentication systems, and are frequently under-documented and therefore under-tested. Shadow APIs — endpoints that exist but appear in no official documentation — are a persistent problem.
Layer 5: Cloud Resources
Object storage buckets (S3, Azure Blob, GCP Storage), serverless functions, cloud databases with public endpoints, and cloud-native services exposed through misconfigured permissions. Cloud resources are frequently created by developers for specific projects, used temporarily, and then abandoned with their public access settings intact.
Discovery Phase: Passive Reconnaissance
Passive reconnaissance collects information about your attack surface without sending traffic directly to your targets. This uses publicly available data sources: DNS records, certificate transparency logs, internet-wide scans, and web archives. It's the starting point for any ASM program because it reveals what's already publicly enumerable — the same information an attacker would gather before launching an active attack.
Subdomain enumeration with subfinder
Subfinder from ProjectDiscovery is the standard tool for passive subdomain discovery. It queries over 40 passive sources simultaneously: certificate transparency logs (crt.sh), DNS datasets (SecurityTrails, Shodan, Censys), threat intelligence feeds, and web archives.
# Install subfinder
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
# Basic subdomain enumeration
subfinder -d example.com -o subdomains.txt
# Verbose output with source attribution
subfinder -d example.com -v -o subdomains.txt
# Use multiple configured API keys for broader coverage
subfinder -d example.com -all -o subdomains.txt
# Enumerate multiple domains from a file
subfinder -dL domains.txt -o all-subdomains.txt
Configure API keys in ~/.config/subfinder/provider-config.yaml for SecurityTrails, Shodan, Censys, and other sources — this substantially increases subdomain coverage, especially for smaller domains where crt.sh alone may miss subdomains that appear in threat intelligence databases.
Comprehensive enumeration with amass
OWASP Amass goes further than subfinder, combining passive sources with active DNS brute-forcing and network mapping. It builds a relationship graph between discovered assets, which helps identify IP ranges and ASNs associated with your target organization.
# Passive-only enumeration (no direct target contact)
amass enum -passive -d example.com -o amass-passive.txt
# Active enumeration (includes DNS brute-force)
amass enum -active -d example.com -o amass-active.txt
# Full enumeration with IP ranges and ASN mapping
amass enum -d example.com -ip -o amass-full.txt
# Visualize the asset graph
amass viz -d3 -dir ~/.config/amass/
DNS resolution and probing with dnsx
After subfinder and amass produce a subdomain list, many discovered entries will be defunct DNS records pointing nowhere. dnsx resolves each subdomain and filters to those with live DNS records, dramatically reducing the working set before you do any HTTP probing.
# Resolve subdomains and filter to live ones
cat subdomains.txt | dnsx -silent -o live-subdomains.txt
# Resolve with A record output (IP addresses)
cat subdomains.txt | dnsx -a -resp -o resolved.txt
# Filter for specific record types
cat subdomains.txt | dnsx -cname -resp -o cname-records.txt
# CNAME records pointing to external services are subdomain takeover candidates
# Look for: amazonaws.com, github.io, heroku.com, netlify.app, etc.
CNAME records pointing to external service providers are particularly important — these are potential subdomain takeover targets. If docs.example.com has a CNAME to example.github.io and that GitHub Pages deployment no longer exists, an attacker can claim that GitHub Pages name and serve content from your subdomain.
HTTP service discovery with httpx
httpx probes each live subdomain for HTTP/HTTPS services, returning status codes, titles, content lengths, web server headers, and technology fingerprints. This turns your list of subdomains into a structured inventory of web services.
# Probe for HTTP services across all live subdomains
cat live-subdomains.txt | httpx -silent -status-code -title -tech-detect -o http-services.txt
# Full fingerprinting with content length and web server
cat live-subdomains.txt | httpx -status-code -title -content-length -web-server -tech-detect -o full-inventory.txt
# Find services running on non-standard ports
cat live-subdomains.txt | httpx -ports 80,443,8080,8443,3000,4000,4443,5000,8000,8001,9000 -silent -o all-ports.txt
# JSON output for pipeline processing
cat live-subdomains.txt | httpx -json -o services.json | jq '.url, .status_code, .title'
A 200 status on admin.example.com with title "Grafana" and no authentication is an immediate critical finding. A 200 on staging.example.com with title matching your production app tells you there's an unsecured staging environment. A 403 on internal.example.com tells you something is there, even if it's access-controlled.
Active Discovery: Crawling and Content Extraction
Passive reconnaissance tells you what subdomains and services exist. Active discovery reveals what's inside them: the URLs, API endpoints, JavaScript bundles, and embedded references that make up the actual application attack surface.
Web crawling with katana
ProjectDiscovery's katana is a fast, configurable web crawler designed for security use cases. It handles JavaScript-heavy SPAs, extracts endpoints from JS files, follows redirects, and supports headless browser mode for fully rendered JavaScript execution.
# Basic crawl of a target
katana -u https://app.example.com -o crawled-urls.txt
# Headless mode for JavaScript-rendered content
katana -u https://app.example.com -headless -o crawled-urls.txt
# Crawl with JavaScript parsing and endpoint extraction
katana -u https://app.example.com -jc -o crawled-urls.txt
# Crawl multiple targets from httpx output
cat http-services.txt | katana -list - -o all-endpoints.txt
# Scope crawling to specific domain
katana -u https://app.example.com -d 5 -scope example.com -o scoped-crawl.txt
JavaScript file analysis for endpoint extraction
Modern web applications bundle their routing logic, API calls, and sometimes configuration data into JavaScript files. These JS bundles are a goldmine for attack surface discovery — they often contain API endpoint paths, internal service URLs, hardcoded environment references, and occasionally credentials or API keys left in by developers who assumed client-side code wasn't readable.
# Extract all JS file URLs from a crawl
cat crawled-urls.txt | grep "\.js$" | sort -u > js-files.txt
# Download and extract endpoints from JS files using getJS
getJS --url https://app.example.com --output js-endpoints.txt
# Use LinkFinder to extract endpoints from JS files
python3 linkfinder.py -i https://app.example.com/static/bundle.js -o cli
# Extract from multiple JS files
cat js-files.txt | while read url; do
python3 linkfinder.py -i "$url" -o cli 2>/dev/null
done | sort -u > all-js-endpoints.txt
# Look for sensitive patterns in JS files
curl -s https://app.example.com/static/app.js | grep -Ei \
"(api_key|apikey|secret|password|token|aws_|bearer|auth)"
Pay particular attention to JS files that reference internal hostnames (api.internal.example.com), environment-specific configurations (staging-api.example.com), or path prefixes that don't appear in the visible application (/admin/v2/, /internal/).
Wayback Machine mining
The Wayback Machine and Common Crawl have indexed web content for decades. Endpoints that exist in historical crawl data but no longer appear in current crawls are often orphaned endpoints — still live on the server, not linked from anywhere, and therefore untested. These are disproportionately likely to be vulnerable, because they're maintained by nobody.
# Fetch historical URLs from Wayback Machine using waybackurls
echo "example.com" | waybackurls > wayback-urls.txt
# Use gau (getallurls) for combined historical sources
gau example.com --providers wayback,commoncrawl,otx > historical-urls.txt
# Extract unique paths from historical data
cat historical-urls.txt | grep "example.com" | \
grep -v ".(png|jpg|gif|css|woff|ico)$" | \
sort -u > historical-paths.txt
# Find historically seen endpoints that aren't in current crawl
comm -23 \
<(sort historical-paths.txt) \
<(sort crawled-urls.txt) \
> orphaned-candidates.txt
# Probe orphaned candidates for live status
cat orphaned-candidates.txt | httpx -silent -status-code
API Surface Discovery
APIs deserve their own discovery pass. Web crawlers follow HTML links; they don't enumerate REST API endpoints that aren't referenced in the UI. API surface discovery requires different techniques.
OpenAPI and Swagger spec discovery
Many applications expose their API documentation publicly, often unintentionally. OpenAPI/Swagger specs are particularly valuable — they enumerate every endpoint, parameter, and response schema for you, which is exactly what a pentester needs and what you want to find before an attacker does.
# Common paths where API docs are exposed
/swagger.json
/swagger.yaml
/openapi.json
/openapi.yaml
/api/swagger.json
/api/openapi.json
/api/docs
/api/v1/docs
/api/v2/docs
/docs/api
/redoc
/api-docs
/v1/api-docs
/v2/api-docs
/.well-known/openapi
# Check them all in one pass
cat api-spec-paths.txt | \
sed 's|^|https://app.example.com|' | \
httpx -silent -status-code -content-length | \
grep " 200 "
Postman collection exposure
Development teams frequently share Postman collections containing all API endpoints, including internal and admin routes. These sometimes end up indexed by search engines or left in publicly accessible locations.
# Search for exposed Postman collections
# Google: site:example.com filetype:json "postman_collection"
# Or check common paths:
/postman_collection.json
/api/postman_collection.json
/docs/postman.json
# Shodan search for Postman collections:
# http.title:"Postman" hostname:example.com
Common API path brute-forcing
For APIs without public documentation, enumerate common paths using a targeted wordlist. ffuf (Fuzz Faster U Fool) is the standard tool for this.
# Install ffuf
go install github.com/ffuf/ffuf/v2@latest
# Enumerate API paths with a common wordlist
ffuf -u https://api.example.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
-mc 200,201,204,301,302,401,403 \
-o api-paths.json
# Version enumeration
ffuf -u https://api.example.com/FUZZ/users \
-w versions.txt \ # v1, v2, v3, api, api/v1, etc.
-mc 200,201,401
# Combine discovered base paths with common resources
ffuf -u https://api.example.com/v1/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/api/objects.txt \
-mc 200,201,204,301,302,401,403
Pay attention to 401 and 403 responses — these indicate endpoints that exist but require authentication. They belong on your attack surface inventory even if they're currently access-controlled. An authentication bypass vulnerability, a misconfigured CORS policy, or a future configuration change could expose them.
Cloud Asset Discovery
Cloud resources are the fastest-growing part of the attack surface for most organizations, and the least consistently tracked. Developers spin up S3 buckets, Azure blobs, and GCP storage buckets as part of normal workflow. Security teams rarely have visibility into what's being created.
S3 bucket enumeration
# Check for common S3 bucket naming patterns
# Buckets are typically named: company-name, company-env, company-service
# Example patterns for "example":
example
example-prod
example-staging
example-dev
example-backup
example-assets
example-uploads
example-static
example-logs
example-data
# Use S3Scanner to check bucket existence and access
python3 s3scanner.py --bucket-file bucket-names.txt
# Or use AWS CLI to probe specific buckets
aws s3 ls s3://example-staging --no-sign-request 2>&1
# If the command returns file listings without credentials — the bucket is public
# Use nuclei with cloud templates
nuclei -t cloud/aws/ -u example.com -o cloud-findings.txt
Azure Blob and GCP Storage
# Azure Blob Storage — check common container names
# Format: https://<account>.blob.core.windows.net/<container>/
curl -s "https://example.blob.core.windows.net/?comp=list"
curl -s "https://examplebackup.blob.core.windows.net/backups?restype=container&comp=list"
# GCP Storage — check for public bucket access
curl -s "https://storage.googleapis.com/example-backup/"
curl -s "https://storage.googleapis.com/example-prod-assets/"
# BlobHunter for Azure storage enumeration
python3 BlobHunter.py -a example -o azure-findings.txt
# GrayhatWarfare for indexed public cloud storage
# https://buckets.grayhatwarfare.com — searchable index of public cloud files
Orphaned and Shadow IT Discovery
Shadow IT — systems created outside formal IT governance — and orphaned assets — systems that were formally created but then abandoned without proper decommissioning — are disproportionately likely to become breach entry points. They're maintained by nobody, monitored by nobody, and patched by nobody.
Finding orphaned subdomains
Orphaned subdomains typically show one of these signatures: a CNAME pointing to an external service that no longer has a corresponding resource (subdomain takeover); an A record pointing to an IP that no longer belongs to your organization; or a live service returning an error page from a cloud provider indicating the underlying resource was deleted.
# Find subdomains with external CNAMEs
cat subdomains.txt | dnsx -cname -resp | grep -v "example.com" > external-cnames.txt
# Check for common subdomain takeover indicators
# These services are commonly involved in takeover:
# amazonaws.com, github.io, heroku.com, netlify.app, fastly.net,
# pantheon.io, readme.io, wpengine.com, zendesk.com, shopify.com
# Use subjack to automate subdomain takeover checking
subjack -w subdomains.txt -t 100 -ssl -o takeover-findings.txt
# nuclei templates for subdomain takeover
nuclei -l subdomains.txt -t takeovers/ -o takeover-nuclei.txt
Identifying staging and development environments
Development environments are reliably less secure than production: they often run older software versions, have debug endpoints enabled, use weaker credentials, have broader CORS policies, and may contain production data copies loaded for testing. Finding them is straightforward — they're named predictably.
# Common staging/dev subdomain patterns to enumerate
dev.example.com
staging.example.com
stage.example.com
uat.example.com
test.example.com
qa.example.com
preprod.example.com
preview.example.com
beta.example.com
sandbox.example.com
demo.example.com
internal.example.com
api-dev.example.com
api-staging.example.com
admin-dev.example.com
new.example.com
old.example.com
v2.example.com
next.example.com
# Add these to subfinder output and probe with httpx
cat dev-patterns.txt | httpx -status-code -title -tech-detect
When you find a staging environment returning a 200, immediately check whether it requires authentication, whether debug endpoints are exposed (/debug, /phpinfo, /_debug, /__debug__), and whether it's running a current software version. Staging environments with production data and no authentication are consistently one of the most impactful findings in penetration tests.
Change Detection and Continuous Monitoring
A one-time ASM discovery exercise is useful but insufficient. Attack surfaces change constantly: new microservices are deployed, marketing teams spin up campaign landing pages, developers create test environments, and cloud resources are provisioned as part of regular work. Continuous monitoring detects these changes as they happen.
Building a monitoring pipeline
# Daily subdomain monitoring script
#!/bin/bash
DOMAIN="example.com"
DATE=$(date +%Y-%m-%d)
PREV_DATE=$(date -d "yesterday" +%Y-%m-%d)
DATA_DIR="/opt/asm-data"
# Run discovery
subfinder -d $DOMAIN -all -silent > "$DATA_DIR/$DATE-subdomains.txt"
# Compare with previous day
if [ -f "$DATA_DIR/$PREV_DATE-subdomains.txt" ]; then
# New subdomains (in today, not yesterday)
NEW=$(comm -23 \
<(sort "$DATA_DIR/$DATE-subdomains.txt") \
<(sort "$DATA_DIR/$PREV_DATE-subdomains.txt"))
if [ -n "$NEW" ]; then
echo "NEW SUBDOMAINS DETECTED: $DATE" | \
mail -s "ASM Alert: New Subdomains" security@example.com
echo "$NEW" | \
mail -s "ASM Alert: New Subdomains" security@example.com
fi
# Probe new subdomains immediately
echo "$NEW" | httpx -silent -status-code -title \
>> "$DATA_DIR/$DATE-new-services.txt"
fi
Alerting on new services
Not every new subdomain is a security problem — but every new internet-exposed service should be reviewed. Effective monitoring sends alerts that are actionable rather than noisy: new subdomains with live HTTP services get immediate attention; changes to CNAME records get reviewed for takeover risk; newly opened ports on known IP ranges get flagged for service identification.
# Monitor for new ports on known IP ranges using naabu
naabu -host $IP_RANGE -top-ports 1000 -o "$DATA_DIR/$DATE-ports.txt"
# Diff against previous scan
diff "$DATA_DIR/$PREV_DATE-ports.txt" "$DATA_DIR/$DATE-ports.txt" | \
grep "^>" | \
grep -v "^---" > "$DATA_DIR/$DATE-new-ports.txt"
# Monitor certificate transparency for new certs issued for your domain
# ct-monitor or certstream — catches new subdomains before DNS propagation
python3 ct-monitor.py --domain example.com --slack-webhook $WEBHOOK_URL
Attack Surface Reduction
Discovery and monitoring identify what exists. Reduction eliminates what shouldn't. This is the phase most organizations underinvest in — it requires coordination between security teams and engineering teams to actually decommission unused assets rather than just knowing they exist.
The reduction priority matrix:
| Asset Type | Risk Level | Action |
|---|---|---|
| Orphaned subdomain (takeover risk) | Critical | Remove DNS record immediately |
| Public cloud storage with sensitive data | Critical | Restrict access, audit contents, rotate any exposed credentials |
| Staging environment with production data | High | Add authentication or remove production data; schedule decommission |
| Admin interface exposed publicly | High | Restrict to VPN or IP allowlist |
| Debug endpoint on production | High | Disable in production configuration immediately |
| Deprecated API version (v1 alongside v2) | Medium | Plan deprecation with timeline; ensure it's in scan scope until removed |
| Unused port open on internet-facing server | Medium | Close at firewall/security group level |
| Redundant public cloud storage bucket | Low-Medium | Make private or delete if unused |
Surface reduction is not just a security practice — it's also an operational one. Fewer exposed services means fewer systems to patch, fewer credentials to rotate, and fewer places a misconfiguration can cause a production incident. The security team and engineering leadership should be aligned on this.
Tools Reference: The ASM Toolkit
The ProjectDiscovery toolkit has become the de facto standard for ASM and reconnaissance. These tools are open source, actively maintained, designed to work together in pipelines, and used by professional pentesters and red teams worldwide.
| Tool | Purpose | Key feature |
|---|---|---|
subfinder |
Passive subdomain discovery | 40+ passive sources; API key support for broad coverage |
amass |
Comprehensive ASM enumeration | Asset graph, ASN mapping, active + passive modes |
dnsx |
DNS resolution and filtering | Fast bulk resolution; CNAME, A, MX, TXT record extraction |
httpx |
HTTP service probing | Status codes, titles, tech detection, screenshot capability |
katana |
Web crawling | JS-aware crawling, headless browser mode, endpoint extraction |
naabu |
Port scanning | Fast SYN scanning; integrates directly with httpx |
nuclei |
Vulnerability scanning | Template-based; cloud, takeover, exposure templates built-in |
ffuf |
Web fuzzing | Fast directory and API endpoint brute-forcing |
| Shodan | Internet-wide scan data | Find internet-exposed services by org, IP range, or certificate |
| Censys | Internet asset intelligence | Certificate + service data; better structured than Shodan for ASM |
| SecurityTrails | DNS and domain history | Historical DNS records; find subdomains not in current DNS |
| crt.sh | Certificate transparency search | Free; indexes all publicly issued certificates including SANs |
The complete passive-to-active pipeline
# Full ASM pipeline — from domain to tested inventory
DOMAIN="example.com"
OUTPUT_DIR="./asm-$(date +%Y%m%d)"
mkdir -p $OUTPUT_DIR
# Step 1: Passive subdomain discovery
echo "[*] Running passive subdomain discovery..."
subfinder -d $DOMAIN -all -silent > $OUTPUT_DIR/subdomains-raw.txt
amass enum -passive -d $DOMAIN -silent >> $OUTPUT_DIR/subdomains-raw.txt
sort -u $OUTPUT_DIR/subdomains-raw.txt > $OUTPUT_DIR/subdomains.txt
echo "[+] Found $(wc -l < $OUTPUT_DIR/subdomains.txt) unique subdomains"
# Step 2: DNS resolution
echo "[*] Resolving subdomains..."
cat $OUTPUT_DIR/subdomains.txt | dnsx -silent -a -resp \
> $OUTPUT_DIR/resolved.txt
# Step 3: HTTP service probing
echo "[*] Probing for HTTP services..."
cat $OUTPUT_DIR/subdomains.txt | \
httpx -silent -status-code -title -tech-detect -content-length \
-ports 80,443,8080,8443,3000,4000,5000,8000,8001,9000 \
-o $OUTPUT_DIR/http-services.txt
# Step 4: Feed live services into nuclei for vulnerability scanning
echo "[*] Running nuclei against live services..."
cat $OUTPUT_DIR/http-services.txt | awk '{print $1}' | \
nuclei -t exposures/ -t takeovers/ -t cloud/ -t misconfiguration/ \
-severity critical,high,medium \
-o $OUTPUT_DIR/nuclei-findings.txt
echo "[+] ASM pipeline complete. Results in $OUTPUT_DIR/"
Integrating ASM into DevSecOps
Manual ASM exercises are valuable but insufficient at organizational scale. Engineering teams deploy new services continuously — a weekly manual scan creates a six-day window where new infrastructure goes unmonitored. The goal is to integrate ASM into the development lifecycle so the security inventory stays current automatically.
CI/CD integration
The most effective integration point is deployment pipelines. Every deployment that creates a new public-facing endpoint should trigger an ASM update: add the new host to the monitored inventory, run immediate service fingerprinting, and queue it for vulnerability scanning.
# GitHub Actions: ASM update on deployment
name: ASM Update on Deploy
on:
deployment_status:
types: [created]
jobs:
asm-update:
runs-on: ubuntu-latest
if: github.event.deployment_status.state == 'success'
steps:
- name: Get deployed URL
id: deploy-url
run: echo "url=${{ github.event.deployment_status.environment_url }}" >> $GITHUB_OUTPUT
- name: Probe new deployment
run: |
# Fingerprint the new deployment
echo "${{ steps.deploy-url.outputs.url }}" | \
httpx -status-code -title -tech-detect
# Add to monitored inventory
curl -X POST https://asm-api.internal/inventory \
-H "Authorization: Bearer ${{ secrets.ASM_API_KEY }}" \
-d '{"url": "${{ steps.deploy-url.outputs.url }}", "env": "${{ github.event.deployment.environment }}"}'
# Trigger vulnerability scan
curl -X POST https://asm-api.internal/scan \
-H "Authorization: Bearer ${{ secrets.ASM_API_KEY }}" \
-d '{"target": "${{ steps.deploy-url.outputs.url }}", "profile": "new-deployment"}'
Weekly automated full scans
Beyond deployment-triggered updates, run a full ASM sweep weekly. This catches services that appeared through mechanisms outside your CI/CD pipeline: manual deployments, cloud resources created directly through the console, or assets from acquisitions and partnerships that weren't properly onboarded.
# Cron-based weekly full ASM sweep
0 2 * * 1 /opt/asm/weekly-full-sweep.sh >> /var/log/asm/weekly.log 2>&1
# weekly-full-sweep.sh
#!/bin/bash
for domain in $(cat /opt/asm/domains.txt); do
echo "=== Sweeping $domain ==="
subfinder -d $domain -all -silent | \
dnsx -silent | \
httpx -silent -status-code -title | \
tee /opt/asm/current/$domain.txt
# Diff against last week
diff /opt/asm/last-week/$domain.txt \
/opt/asm/current/$domain.txt | \
grep "^>" > /opt/asm/changes/$domain-$(date +%Y%m%d).txt
done
# Copy current to last-week for next run
cp /opt/asm/current/* /opt/asm/last-week/
Ownership tracking
ASM produces value not just from finding unknown assets, but from establishing who owns each asset. An inventory without ownership data is a list you can't act on. Every asset in the inventory should have a team owner — the engineering team responsible for it, the person who can authorize its decommissioning, and the SLA for responding to findings on that asset.
Build this into your discovery pipeline: when a new asset is identified, automatically look up the DNS registrar or cloud account owner, cross-reference with your deployment metadata, and create a ticket assigned to the responsible team. Unknown ownership should itself be treated as a finding.
How Continuous Scanning Completes the ASM Picture
ASM without vulnerability scanning is a map without a threat assessment. Knowing you have 847 subdomains and 23 live web services is useful; knowing which of those services have authentication bypass vulnerabilities, exposed admin panels, or outdated software with known CVEs is actionable.
The gap most organizations have is not in their ability to run a scan — it's in the completeness of what they scan and the frequency with which they scan it. A quarterly pentest covers the assets you think to include in scope. Continuous automated scanning covers everything in your ASM inventory, run on a schedule that reflects the pace at which your infrastructure actually changes.
The effective model:
- ASM discovery runs continuously — daily passive subdomain sweeps, weekly full enumeration, deployment-triggered inventory updates
- The ASM inventory feeds directly into your scanning scope — every new asset discovered gets queued for a baseline security scan
- Continuous scanning runs against the full inventory on a regular schedule — not just the domains you remember to include
- Change detection triggers immediate scans when new assets appear or existing assets change significantly
- Findings are tracked per-asset with ownership, so nothing falls through the cracks
This is the operational model that security teams at well-resourced companies have been running for years. The tools have been open source and available to everyone. What's been missing for smaller teams is the operational overhead — running and maintaining the infrastructure, keeping signatures current, triaging findings, and keeping the inventory synchronized with fast-moving infrastructure. That operational burden is what automated scanning platforms are designed to eliminate.
Ironimo gives you continuous, automated security scanning against your full attack surface — not just the endpoints you remember to test. Built on Kali Linux's scanner toolkit, it discovers and tests your web application surface on your schedule.
Start free scan