Guide · AWS Inspector · Finding Management
AWS Inspector Findings — Inspector Score, Suppression Rules, EventBridge, and Security Hub Integration
An AWS Inspector finding is more than a CVSS score attached to a CVE — it is a continuously updated risk record that incorporates exploit availability, network reachability context, and threat intelligence to produce the Inspector Score (0.0–10.0), which is the field you should triage on, not raw CVSS. Understanding how findings are created, updated, suppressed, and routed to downstream systems (EventBridge, Security Hub, Jira) is what separates teams that act on Inspector data from teams that disable it because "there are too many findings." The key discipline: create suppression rules for accepted risks with documented justification, alert on new CRITICAL/HIGH findings via EventBridge, and measure MTTR (mean time to remediation) on Inspector Score ≥ 7.0 findings as your primary security KPI.
TL;DR
Triage on Inspector Score ≥ 7.0, not CVSS. Use ListFindings with --sort-criteria INSPECTOR_SCORE DESC to see the most critical findings first. Create suppression rules via CreateFilter --action SUPPRESS for accepted risks. Route new CRITICAL findings to Slack or PagerDuty via EventBridge. Enable Security Hub to see Inspector findings alongside GuardDuty and Security Hub Standards. For the Inspector overview see the overview. For EC2-specific guidance see the EC2 guide. For ECR see the ECR guide. For Lambda see the Lambda guide.
Inspector Score calculation
The Inspector Score starts from the NVD CVSS v3.1 base score and is then adjusted by Inspector-proprietary signals. The adjustments are always upward — the Inspector Score is never lower than the CVSS base score:
| Signal | Adjustment | Source |
|---|---|---|
| CVE in CISA KEV (Known Exploited Vulnerabilities) | Significant boost — typically pushes to CRITICAL band | CISA KEV catalog, updated daily |
| Public exploit available (Exploit-DB, Metasploit module) | Moderate boost — often +1.0 to +2.5 | Inspector threat intelligence feeds |
| Active exploitation in the wild | Large boost — often reaches CRITICAL regardless of base CVSS | Threat intelligence sharing |
| Network reachability (EC2 only) | Boost if the affected port is internet-reachable | VPC topology analysis |
| No public exploit, no active exploitation | No adjustment — Inspector Score = CVSS base | — |
A practical example: CVE-2021-44228 (Log4Shell) had a CVSS base of 10.0 and was in CISA KEV — its Inspector Score was 10.0 from day one. A lesser-known CVE in the same library with CVSS base 5.0 and no public exploit has an Inspector Score of 5.0. The difference is what you prioritize patching first.
Querying findings
The ListFindings API supports rich filter criteria across finding type, severity, resource type, CVE ID, package name, resource tag, and more. Always include a sort by Inspector Score descending to surface the most critical findings first:
# Top CRITICAL and HIGH findings across all resources, sorted by risk
aws inspector2 list-findings \
--filter-criteria '{
"severity": [
{"comparison":"EQUALS","value":"CRITICAL"},
{"comparison":"EQUALS","value":"HIGH"}
],
"findingStatus": [{"comparison":"EQUALS","value":"ACTIVE"}]
}' \
--sort-criteria '{"field":"INSPECTOR_SCORE","sortOrder":"DESC"}' \
--max-results 25 \
--query 'findings[].{Score:inspectorScore,Severity:severity,Type:type,Resource:resources[0].id,CVE:packageVulnerabilityDetails.vulnerabilityId,Fix:packageVulnerabilityDetails.vulnerablePackages[0].fixedInVersion}' \
--output table
# Findings for a specific CVE across all resources (blast radius assessment)
aws inspector2 list-findings \
--filter-criteria '{
"vulnerabilityId": [{"comparison":"EQUALS","value":"CVE-2024-XXXXX"}]
}' \
--query 'findings[].{Resource:resources[0].id,Type:resources[0].type,Status:status,Score:inspectorScore}' \
--output table
# Findings by resource tag (e.g., all production resources)
aws inspector2 list-findings \
--filter-criteria '{
"resourceTags": [{"comparison":"EQUALS","key":"Environment","value":"production"}],
"findingStatus": [{"comparison":"EQUALS","value":"ACTIVE"}]
}' \
--sort-criteria '{"field":"INSPECTOR_SCORE","sortOrder":"DESC"}' \
--query 'findings[].{Score:inspectorScore,Severity:severity,Resource:resources[0].id,CVE:packageVulnerabilityDetails.vulnerabilityId}' \
--output table
Finding lifecycle and status
Inspector findings have three statuses:
| Status | Meaning | How it transitions |
|---|---|---|
| ACTIVE | Vulnerability confirmed present and unresolved | Initial state; returns here if a suppression rule is removed or a closed finding's package is re-introduced |
| SUPPRESSED | Finding matches a suppression rule — hidden from default dashboard view | Set when a matching CreateFilter/UpdateFilter rule is applied; reverts to ACTIVE if the rule is deleted |
| CLOSED | Vulnerability resolved: package updated to fixed version, resource terminated, or resource deregistered from Inspector | Inspector automatically closes when the package is updated past the fixedInVersion or the resource no longer exists |
Inspector automatically closes findings when the vulnerability is resolved — you do not need to manually close them. This is what enables MTTR measurement: lastObservedAt when status transitions to CLOSED minus createdAt gives the remediation time. Query this directly from the findings API:
# MTTR calculation for CLOSED findings in the past 30 days
aws inspector2 list-findings \
--filter-criteria '{
"findingStatus": [{"comparison":"EQUALS","value":"CLOSED"}],
"lastObservedAt": [{"startInclusive":"2026-09-09T00:00:00Z","endInclusive":"2026-10-09T00:00:00Z"}],
"severity": [{"comparison":"EQUALS","value":"CRITICAL"},{"comparison":"EQUALS","value":"HIGH"}]
}' \
--query 'findings[].{CVE:packageVulnerabilityDetails.vulnerabilityId,Created:createdAt,Closed:lastObservedAt,Score:inspectorScore}' \
--output json | jq '[.[] | {cve:.CVE, score:.Score, days_open: ((.Closed | fromdateiso8601) - (.Created | fromdateiso8601)) / 86400}] | sort_by(.days_open) | reverse'
Suppression rules (filters)
Inspector calls suppression rules "filters" in the API — the --action SUPPRESS flag on CreateFilter creates a suppression rule. Filters can also have action NONE to create saved searches for dashboards without suppressing findings.
# Suppression rule: specific CVE on development resources
aws inspector2 create-filter \
--name "suppress-CVE-2024-XXXXX-dev" \
--description "CVE-2024-XXXXX in libcurl — MCP server data path does not use affected feature; compensating control in JIRA-1234" \
--filter-criteria '{
"vulnerabilityId": [{"comparison":"EQUALS","value":"CVE-2024-XXXXX"}],
"resourceTags": [{"comparison":"EQUALS","key":"Environment","value":"development"}]
}' \
--action SUPPRESS \
--reason "Non-exploitable in data path; tracked for remediation in next quarterly cycle"
# Suppression rule: all findings on terminated instance AMI pattern (decommissioned base)
aws inspector2 create-filter \
--name "suppress-old-base-ami" \
--description "Old base AMI ami-0abc1234 — all instances migrated to new AMI; pending cleanup" \
--filter-criteria '{
"ec2InstanceImageId": [{"comparison":"EQUALS","value":"ami-0abc1234"}]
}' \
--action SUPPRESS \
--reason "All instances on this AMI are in process of termination — tracked in ops ticket OPS-789"
Governance practice: require a JIRA/GitHub issue reference in --description and a clear technical reason in --reason for every suppression rule. Schedule quarterly reviews of all suppression rules — a rule suppressing a CVE may become invalid if the threat model changes or if an exploit is published after the rule was created.
# List all suppression rules with age (to identify stale ones)
aws inspector2 list-filters \
--action SUPPRESS \
--query 'filters[].{Name:name,Created:createdAt,Reason:reason,Criteria:filterCriteria}' \
--output json | jq '.[] | {name, age_days: (("2026-10-09T00:00:00Z" | fromdateiso8601) - (.Created | fromdateiso8601)) / 86400 | floor, reason}'
EventBridge integration for real-time alerting
Inspector publishes events to EventBridge for every new finding and every finding status change. Use EventBridge rules to route CRITICAL/HIGH findings to Slack, PagerDuty, or a ticket queue in real time — this is how you achieve the 24-hour SLA for CRITICAL findings without manually watching the Inspector console.
# EventBridge rule: alert on new CRITICAL findings across all resource types
aws events put-rule \
--name "inspector-critical-findings-alert" \
--event-pattern '{
"source": ["aws.inspector2"],
"detail-type": ["Inspector2 Finding"],
"detail": {
"severity": ["CRITICAL"],
"status": ["ACTIVE"]
}
}' \
--state ENABLED \
--description "Route new CRITICAL Inspector findings to PagerDuty"
# Add SNS target to the rule (SNS then forwards to PagerDuty/Slack/email)
aws events put-targets \
--rule "inspector-critical-findings-alert" \
--targets '[{
"Id": "inspector-critical-sns",
"Arn": "arn:aws:sns:us-east-1:123456789012:security-alerts",
"InputTransformer": {
"InputPathsMap": {
"score": "$.detail.inspectorScore",
"cve": "$.detail.packageVulnerabilityDetails.vulnerabilityId",
"resource": "$.detail.resources[0].id",
"severity": "$.detail.severity"
},
"InputTemplate": "\"CRITICAL Inspector finding: (score ) on — severity . Review at https://console.aws.amazon.com/inspector/v2/home\""
}
}]'
The InputTransformer lets you extract key fields from the finding and format a human-readable alert. Key fields available in the event: inspectorScore, severity, status, type, resources[0].id, packageVulnerabilityDetails.vulnerabilityId, packageVulnerabilityDetails.vulnerablePackages[0].fixedInVersion.
Security Hub integration
When both Inspector v2 and Security Hub are enabled in the same account and region, Inspector findings are automatically forwarded to Security Hub in ASFF (Amazon Security Finding Format) without any additional configuration. The forwarding is real-time — findings appear in Security Hub within seconds of Inspector creating them.
Inspector findings in Security Hub appear with ProductArn: arn:aws:securityhub:REGION::product/aws/inspector. They are subject to Security Hub automation rules — you can use Security Hub automation rules to route, suppress, or update Inspector findings alongside findings from GuardDuty and Security Hub Standards.
# View Inspector findings from Security Hub (cross-service unified view)
aws securityhub get-findings \
--filters '{
"ProductName": [{"Value":"Inspector","Comparison":"EQUALS"}],
"SeverityLabel": [{"Value":"CRITICAL","Comparison":"EQUALS"}],
"WorkflowStatus": [{"Value":"NEW","Comparison":"EQUALS"}]
}' \
--sort-criteria '[{"Field":"SeverityNormalized","SortOrder":"desc"}]' \
--query 'Findings[].{Id:Id,Title:Title,Severity:Severity.Label,Resource:Resources[0].Id,Status:Workflow.Status}' \
--output table | head -30
Important distinction: WorkflowStatus in Security Hub (NEW/NOTIFIED/RESOLVED/SUPPRESSED) is separate from Inspector's findingStatus (ACTIVE/SUPPRESSED/CLOSED). When you suppress a finding in Inspector (via Inspector filter rules), the Inspector finding status becomes SUPPRESSED — but the Security Hub Workflow.Status remains NEW unless you also update it via BatchUpdateFindings in Security Hub. Teams that triage in Security Hub should use Security Hub BatchUpdateFindings to manage workflow status; teams that triage in Inspector should use Inspector filter rules. Do not try to manage both independently for the same findings — pick one system as the source of truth.
# Update Security Hub workflow status for Inspector findings (bulk resolve)
aws securityhub batch-update-findings \
--finding-identifiers '[
{"Id":"arn:aws:inspector2:us-east-1:123456789012:finding/abc123","ProductArn":"arn:aws:securityhub:us-east-1::product/aws/inspector"}
]' \
--workflow '{"Status":"RESOLVED"}' \
--note '{"Text":"Patched in deploy v2.1.4 on 2026-10-09","UpdatedBy":"security-team"}'
Account-level aggregation and reporting
# Severity distribution across all resources in account
aws inspector2 list-findings-aggregations \
--aggregation-type ACCOUNT \
--account-aggregation-input '{"findingType":"PACKAGE_VULNERABILITY","sortOrder":"DESC","sortBy":"CRITICAL"}' \
--query 'responses[].accountAggregation.{AccountId:accountId,Critical:severityCounts.critical,High:severityCounts.high,Medium:severityCounts.medium}' \
--output table
# Top packages with the most findings (useful for prioritizing library upgrades)
aws inspector2 list-findings-aggregations \
--aggregation-type PACKAGE \
--package-aggregation-input '{"packageNames":[],"sortOrder":"DESC","sortBy":"CRITICAL"}' \
--query 'responses[].packageAggregation.{Package:packageName,Critical:severityCounts.critical,High:severityCounts.high,Version:affectedVersion}' \
--output table | head -20
The package aggregation view is the most actionable for MCP server teams: it shows which library has the most CRITICAL findings across all your deployed resources. If openssl appears at the top with 5 CRITICAL findings across 12 EC2 instances, patching OpenSSL in your base AMI and redeploying resolves all 12 instances at once — far more efficient than triaging instance-by-instance.
Failure modes reference
| Failure | Symptom | Fix |
|---|---|---|
| Findings not appearing in Security Hub | Inspector enabled but no Inspector findings in Security Hub | Inspector-to-Security Hub integration is automatic only if both services are enabled in the same region and account; verify Security Hub is enabled with aws securityhub describe-hub |
| Suppressed in Inspector but still NEW in Security Hub | Inspector filter rule suppresses finding but Security Hub still shows it as NEW | Inspector and Security Hub workflow states are independent; update Security Hub WorkflowStatus via BatchUpdateFindings or create a Security Hub automation rule to suppress findings from Inspector with SUPPRESSED status |
| EventBridge events not firing | New critical findings appear in Inspector but no EventBridge events received | Inspector EventBridge events are regional; verify the event rule is in the same region as Inspector; also verify the EventBridge rule state is ENABLED and the target has correct permissions |
| Finding closed but vulnerability still present | Inspector closed a finding but the package was not actually updated | Inspector may close findings if the resource is terminated or deregistered; verify the resource still exists and re-scan if needed; if resource exists and package is still vulnerable, file AWS support ticket |
| list-findings returns empty despite active findings in console | API returns no findings but console shows findings | Default API filter includes findingStatus=ACTIVE only; add SUPPRESSED to the filter criteria if you need to see suppressed findings; also check region parameter matches where Inspector is enabled |