Whether malware scanning is switched on for compute and for the buckets that accept uploads, plus the scan-by-scan record of what was actually examined and what came back INFECTED
The API supplies the facts, but a human judgement against a documented baseline turns them into evidence.
Fetch
$ aws guardduty list-detectors$ aws guardduty get-detector --detector-id <DETECTOR_ID> --query '{status:Status,publishingFrequency:FindingPublishingFrequency,features:Features[].{name:Name,status:Status,additional:AdditionalConfiguration}}'$ aws guardduty describe-malware-scans --detector-id <DETECTOR_ID> --query 'Scans[].{id:ScanId,type:ScanType,status:ScanStatus,result:ScanResultDetails,started:ScanStartTime,ended:ScanEndTime,files:FileCount,bytes:TotalBytes,resource:ResourceDetails,trigger:TriggerDetails,failure:FailureReason}'$ aws guardduty list-malware-protection-plans$ aws guardduty get-malware-protection-plan --malware-protection-plan-id <PLAN_ID> --query '{protected:ProtectedResource,status:Status,statusReasons:StatusReasons,actions:Actions,role:Role,created:CreatedAt}'$ aws configservice get-compliance-details-by-config-rule --config-rule-name guardduty-malware-protection-enabled --compliance-types NON_COMPLIANTExpected output
A detector id per Region — an empty list means GuardDuty was never enabled there, which is itself the finding. Then the detector's Status ENABLED or DISABLED, its FindingPublishingFrequency of FIFTEEN_MINUTES, ONE_HOUR or SIX_HOURS, and the Features list in which EBS_MALWARE_PROTECTION is the entry that matters, alongside FLOW_LOGS, CLOUD_TRAIL, DNS_LOGS, S3_DATA_EVENTS, EKS_AUDIT_LOGS, RDS_LOGIN_EVENTS, LAMBDA_NETWORK_LOGS, EKS_RUNTIME_MONITORING and RUNTIME_MONITORING with its EC2_AGENT_MANAGEMENT, EKS_ADDON_MANAGEMENT and ECS_FARGATE_AGENT_MANAGEMENT sub-configuration. Then one row per malware scan: ScanId, ScanType GUARDDUTY_INITIATED or ON_DEMAND, ScanStatus RUNNING, COMPLETED, FAILED or SKIPPED, a FailureReason when it failed, ScanStartTime and ScanEndTime, the scanned InstanceArn and its attached volumes, FileCount and TotalBytes actually examined, TriggerDetails carrying the GuardDutyFindingId and a TriggerType of GUARDDUTY or BACKUP, and a ScanResultDetails of CLEAN or INFECTED. Then the Malware Protection plan ids, and per plan the protected S3 bucket with its object prefixes, the scanning role, whether result tagging is on, and a Status of ACTIVE, WARNING or ERROR with StatusReasons naming the problem. Finally, outside GovCloud, the detectors AWS Config marks NON_COMPLIANT for GUARDDUTY_MALWARE_PROTECTION_ENABLED.
Map — what it proves
- recipe1
- recipe— an authored recipe collects evidence for this control
- KSI only— a Key Security Indicator reaches it, but no recipe is authored yet
- orphan— no Key Security Indicator reaches it — a person writes it up instead
What else these families can fetch:SI 10/35 →
GovCloud
GuardDuty runs in both AWS GovCloud (US) Regions and Malware Protection for EC2 works there with one documented gap: instances whose productCode is marketplace are not scanned — GuardDuty skips them and logs the skip reason UNSUPPORTED_PRODUCT_CODE_TYPE, so a SKIPPED scan in GovCloud may be that rather than a misconfiguration. Malware Protection for Backup cannot scan EC2 or EBS recovery points there. The GovCloud differences page records no carve-out for Malware Protection for S3. The last command has nothing to call: GUARDDUTY_MALWARE_PROTECTION_ENABLED is excluded from both AWS GovCloud (US-East) and (US-West) — as it is from the China Regions, Mexico (Central), Asia Pacific (Thailand), (Malaysia) and (Taipei) — so drop it and take the enablement fact from the EBS_MALWARE_PROTECTION feature status in get-detector instead. Also unavailable in GovCloud: the entity lists customisation (IP address lists still work) and the GuardDuty Investigation preview. ARNs use partition arn:aws-us-gov
Notes & assertions
The trap in SI-3 is reading GuardDuty Malware Protection as antivirus. It is not a scheduled sweep of your file systems. A GuardDuty-initiated scan fires only after GuardDuty has already produced a finding indicative of malware on that resource, at most once every 24 hours per resource, and it works agentlessly against snapshots of the attached EBS volumes — so an empty describe-malware-scans list is the expected steady state of a healthy estate and proves nothing about coverage. The two enablement reads prove capability; the scan list proves exercise; neither proves protection. Coverage has a second silent hole: the global GuardDutyExcluded:true tag and your own inclusion or exclusion scan-option tags make GuardDuty initiate a scan and then skip it, so read the scan options next to the tag inventory or a deliberately excluded estate looks like a clean one, and Fargate workloads under EKS or ECS are not scanned at all. Malware Protection for S3 is the closest thing here to SI-3's entry-point requirement — it scans each newly uploaded object and each new version in a configured bucket — but it covers only buckets with an active plan, in the same Region as the plan, in your own account (a delegated GuardDuty administrator cannot enable it on a member account's bucket), and when run independently of GuardDuty there is no detector, so malware produces an EventBridge event, a CloudWatch metric and the optional object tag rather than a GuardDuty finding. What no command here produces is the rest of SI-3: signature or engine currency, since AWS operates the scan engines and exposes no version for you to attest to; periodic full scans; false-positive handling; and the documented response when malicious code is found. Rate those from the plan and the incident record, and keep these reads as the machine half of the answer.
References
- Amazon GuardDuty: Malware Protection for EC2 (GuardDuty-initiated vs on-demand scans, Fargate unsupported) https://docs.aws.amazon.com/guardduty/latest/ug/malware-protection.html
- Amazon GuardDuty: GuardDuty-initiated malware scan (fires only on a malware-indicative finding, 24-hour interval, GuardDutyExcluded tag) https://docs.aws.amazon.com/guardduty/latest/ug/gdu-initiated-malware-scan.html
- Amazon GuardDuty: Malware Protection for S3 (scans newly uploaded objects; independent mode has no detector and so no finding) https://docs.aws.amazon.com/guardduty/latest/ug/gdu-malware-protection-s3.html
- AWS CLI: guardduty get-detector (Features list including EBS_MALWARE_PROTECTION and its status) https://docs.aws.amazon.com/cli/latest/reference/guardduty/get-detector.html
- AWS CLI: guardduty describe-malware-scans (ScanStatus, ScanType, TriggerDetails, ScanResultDetails, FileCount, TotalBytes) https://docs.aws.amazon.com/cli/latest/reference/guardduty/describe-malware-scans.html
- AWS CLI: guardduty list-malware-protection-plans (plan ids for protected resources) https://docs.aws.amazon.com/cli/latest/reference/guardduty/list-malware-protection-plans.html
- AWS CLI: guardduty get-malware-protection-plan (ProtectedResource, Status ACTIVE/WARNING/ERROR, StatusReasons) https://docs.aws.amazon.com/cli/latest/reference/guardduty/get-malware-protection-plan.html
- AWS Config managed rule: guardduty-malware-protection-enabled (GUARDDUTY_MALWARE_PROTECTION_ENABLED, excluded from both AWS GovCloud (US) Regions) https://docs.aws.amazon.com/config/latest/developerguide/guardduty-malware-protection-enabled.html
- Amazon GuardDuty in AWS GovCloud (US) — Malware Protection for EC2 marketplace productCode skip, Backup recovery point limits https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-guardduty.html
This AWS mapping is authored opinion (overlay v3.0.0), versioned separately from the dataset and written against ruleset 2026.07.14.01. The upstream FedRAMP dataset names none of these tools.
The Cloud Native Architecture run (7)
- automatable
- partial — needs judgement
- narrative — no API proves this
Every authored recipe filed under CNA, in the order the plan works them. The mark says how much of the evidence the command produces on its own.
- partialAWS Config compliance results proving the network boundary is controlled — no security group exposes SSH to the internet, groups open to 0.0.0.0/0 only allow authorized ports, and every VPC's default security group denies all trafficcontinuousconfig-network-boundary-protectionAWS Config · Amazon VPC · Amazon EC2
- partialEvery route in or out of the boundary, named and counted — internet gateways, NAT gateways, VPC endpoints and Site-to-Site VPN tunnels — alongside what each boundary device does with traffic that matched no rule: the network ACL entries, the closed default security group, subnets that hand out public IPs, and the firewall policy's stateless and stateful default actionsweeklyboundary-access-points-and-default-denyAmazon VPC · Amazon EC2 · AWS Network Firewall · AWS Config
- partialThe denial-of-service defences that are actually attached to the internet-facing resources — the Shield Advanced subscription and the list of resources it protects, the web ACL's rate-based rules and their limits, whether web ACL logging is on — plus what those defences observed: the attacks Shield recorded over the period and the CloudWatch detection and block counts underneath themdailyddos-protection-and-rate-limitingAWS Shield Advanced · AWS WAF · Amazon CloudWatch · AWS Config
- partialWhether malware scanning is switched on for compute and for the buckets that accept uploads, plus the scan-by-scan record of what was actually examined and what came back INFECTEDyou are hereweeklymalicious-code-protectionAmazon GuardDuty · Amazon EC2 · Amazon S3 · AWS Config
- partialThe machine-generated inventory of every plane on which one part of the system reaches another — VPC peering connections, Transit Gateway attachments, the interface and gateway endpoints this account consumes, the endpoint connections other accounts have made INTO your endpoint service, and the security-group rules that name another group rather than a CIDR — each narrowed to the states that are actually livecontinuousinternal-connection-inventory-and-authorizationAmazon VPC · AWS Transit Gateway · AWS PrivateLink
- partialWhich taint-tracking ruleset actually ran over this repository — the query suite, the languages selected, and the threat model that decides what counts as an untrusted source — together with whether the recurring scan is still scheduled, when it last ran per analysed language, and how many rules were in the run; and then the open findings in the injection families SI-10 is about, identified by the CWE tags the queries carry. The ruleset and the freshness are the load-bearing half: a finding names a sink that exists, but only the run record says the absence of findings means anything at all.continuousinput-validation-taint-analysis-coverageGitHub code scanning · GitHub CodeQL
- partialWhether the queries that find information disclosure through an error message or a stack trace ran over this part of the boundary — which languages were selected, whether the recurring scan is still scheduled and when it last completed — and then the open findings those queries produced, identified by the CWE tags the queries carry rather than by their names. The run record is the load-bearing half here as it is on every scanning recipe: a finding names a leak that exists, and only the record of a scan having run over a selected language makes the absence of findings a statement about anything.continuouserror-handling-information-exposure-scanningGitHub code scanning · GitHub CodeQL · GitHub code security configurations