{"build_date_unix":"unknown","canonical_issues_count":1,"context_aware_rules":["AWS_CRED_003","AWS_CRED_004","AWS_DDB_001","AWS_EC2_001","AWS_EC2_006","AWS_ECS_004","AWS_EVENTBRIDGE_001","AWS_IAM_005","AWS_IAM_020","AWS_IAM_021","AWS_IAM_023","AWS_IAM_025","AWS_IAM_114","AWS_KMS_004","AWS_LAMBDA_004","AWS_OPS_001","AWS_OPS_018","AWS_OPS_026","AWS_OPS_030","AWS_OPS_035","AWS_OPS_037","AWS_OPS_041","AWS_OPS_067","AWS_RDS_001","AWS_RDS_005","AWS_S3_001","AWS_S3_006","AWS_S3_007","AWS_S3_010","AWS_SECRETSMANAGER_004","AWS_SM_001","AWS_SQS_001","AWS_SQS_002","AWS_VPC_006"],"context_reasoning_axes":[{"catch_all":false,"consulted_by":["AWS_LAMBDA_004","AWS_OPS_001"],"description":"Sync (API GW, Function URL) vs async-push (SNS / S3 / EventBridge) vs polled-async (SQS / Kinesis event source mapping). Lambda DLQ only helps async-push.","name":"lambda_invocation_graph"},{"catch_all":false,"consulted_by":["AWS_SQS_001","AWS_SQS_002"],"description":"Which SQS queues are themselves a dead-letter queue (target of another queue's redrive_policy). DLQs do not need their own DLQ; their encryption-at-rest needs are different.","name":"sqs_dlq_identity"},{"catch_all":false,"consulted_by":["AWS_SQS_001"],"description":"KMS-CMK vs AWS-managed vs service-managed (e.g. sqs_managed_sse_enabled = true). Real encryption from any of these — the strict-CMK ask is a separate rule.","name":"encryption_variants"},{"catch_all":false,"consulted_by":["AWS_DDB_001","AWS_OPS_030"],"description":"Whether a resource actively expires its own data (DynamoDB TTL, S3 lifecycle, CloudWatch Logs retention). Ephemeral storage doesn't need PITR / long retention.","name":"data_lifetime"},{"catch_all":false,"consulted_by":["AWS_OPS_026"],"description":"Whether a resource is reachable from the public internet vs internal-only (aws_lb.internal flag, aws_apigateway_rest_api endpoint type, etc.). Public-facing rules (third-party DNS protection, public WAF) can suppress on internal-only resources.","name":"network_exposure"},{"catch_all":false,"consulted_by":["AWS_OPS_035","AWS_OPS_037"],"description":"Whether an IAM principal (role or user) actually holds dangerous grants (Allow + Resource:\"*\" + no Condition, or an attached access key). Shape-based IAM rules that fire on every role/user are suppressed when the principal carries no exploitable permissions.","name":"iam_policy_risk"},{"catch_all":false,"consulted_by":["AWS_OPS_035"],"description":"Whether an IAM role's trust policy is tightly scoped to a non-compute managed-service principal (no EC2/ECS/Lambda/EKS trust, no wildcard, no cross-account ARN). A permissions_boundary provides no meaningful security ceiling for a role that cannot be assumed by an IAM principal or compromised workload — only AWS-internal service calls can reach it.","name":"iam_trust_graph"},{"catch_all":false,"consulted_by":["AWS_OPS_067"],"description":"Whether a stateful resource already sets AWS's own deletion protection (deletion_protection / deletion_protection_enabled). AWS refuses the delete call outright, so a terraform destroy errors instead of dropping the resource — the Terraform-side lifecycle prevent_destroy ask is then a duplicate control.","name":"deletion_guard"},{"catch_all":true,"consulted_by":[],"description":"Whether a resource is disabled via `count = 0` (literal, or a var.X that resolves to 0). A disabled resource is not instantiated, so any finding on it is suppressed as a non-operational concern.","name":"disabled_resource_count"},{"catch_all":true,"consulted_by":[],"description":"For synthesized registry-module pseudo-resources (Phase 6 M3): audytx asserts only on attributes set by an EXPLICIT module input. A finding on a module default, an absent attribute, or an existence-only rule is suppressed — module internals/defaults drift across versions.","name":"module_synthesized_input"},{"catch_all":true,"consulted_by":[],"description":"Whether a resource is tagged as non-production (Environment = dev/staging/test/sandbox/qa/uat/preview/local/nonprod). Medium and Low findings are suppressed on non-prod resources — dev/staging infrastructure legitimately has more relaxed security controls and suppression reduces noise without hiding Critical or High findings. Reach: rules WITHOUT a dedicated dispatch arm in context_suppression_reason (the `_ =>` fallback); rules with a named arm are governed by their own axis and never fall through to this one.","name":"tag_environment"},{"catch_all":false,"consulted_by":["AWS_EC2_006","AWS_IAM_023"],"description":"Whether IMDSv2 (http_tokens = \"required\") is enforced on an EC2 instance via a launch template or account-level aws_ec2_instance_metadata_defaults, even when the aws_instance resource has no direct metadata_options block. Suppresses AWS_EC2_006 (\"no metadata_options block\") and AWS_IAM_023 (\"IMDSv1 + privileged role → SSRF credential theft\") when the SSRF→IMDS chain is already broken by inherited enforcement.","name":"imdsv2_enforcement"},{"catch_all":false,"consulted_by":["AWS_VPC_006"],"description":"Whether an aws_security_group is an EKS node-group or cluster SG — detected via `description`, `name`, or `name_prefix` containing \"eks\" (case-insensitive). EKS node SGs legitimately require all-ports intra-cluster rules (from_port = 0, protocol = -1) sourced from self / another SG for pod-to-pod and control-plane communication within the VPC. AWS_VPC_006 (all-ports-open SG) is suppressed on EKS-identified SGs ONLY when the all-ports rule is intra-cluster — an EKS-named SG that is actually open to 0.0.0.0/0 on all ports is a real finding and still fires.","name":"sg_eks_identity"},{"catch_all":false,"consulted_by":["AWS_ECS_004"],"description":"Whether an aws_ecs_task_definition is a reusable module template rather than a concrete resource — detected when both `family` and `container_definitions` are variable references (stored value starts with \"var.\"). Module templates deliberately omit `task_role_arn` because the caller is expected to supply it via variable. AWS_ECS_004 (missing task_role_arn) is suppressed on module templates to avoid flagging intentionally parameterized module definitions in production module repos.","name":"ecs_module_template"},{"catch_all":false,"consulted_by":["AWS_LAMBDA_004","AWS_OPS_001"],"description":"Whether an aws_lambda_function is a reusable module template — detected when both `function_name` and `handler` are variable references. Module templates leave these to the caller; the Lambda is not yet wired to any invocation source within the module scope. AWS_LAMBDA_004 and AWS_OPS_001 (missing DLQ) are suppressed because the invocation source is external and the DLQ requirement cannot be determined at module definition time.","name":"lambda_module_template"},{"catch_all":false,"consulted_by":["AWS_OPS_018","AWS_SQS_002"],"description":"Whether an aws_sqs_queue is a reusable module template — detected when `visibility_timeout_seconds`, `message_retention_seconds`, and `max_message_size` are all variable references. Root-module queues almost always hard-code at least one of these; module definitions delegate all three to the caller. AWS_OPS_018 (missing CloudWatch alarm) is suppressed because modules are templates and callers own monitoring. AWS_SQS_002 (missing DLQ) is suppressed because the DLQ decision belongs to the caller (e.g. terraform-aws-sqs exposes create_dlq as a caller variable).","name":"sqs_module_template"},{"catch_all":false,"consulted_by":["AWS_EVENTBRIDGE_001"],"description":"Whether an aws_cloudwatch_event_rule should be exempt from the Lambda permission companion check because the Lambda target is defined outside this plan. Detected when no aws_lambda_function resources exist in the plan — the Lambda (and therefore its aws_lambda_permission) belongs to the caller or a separate module, not the one being scanned. AWS_EVENTBRIDGE_001 (missing aws_lambda_permission companion) is suppressed to avoid false positives on EventBridge module repos that provide rules without defining the Lambda target.","name":"eventbridge_external_lambda"},{"catch_all":false,"consulted_by":["AWS_SM_001"],"description":"Whether an aws_secretsmanager_secret has automatic rotation configured by a sibling aws_secretsmanager_secret_rotation resource (resolved from that resource's secret_id reference). AWS_SM_001 fires per-secret and cannot see cross-resource rotation, so without this it is a false positive on every secret whose rotation is managed in a separate resource (the common, recommended pattern). AWS_SM_001 is suppressed when a rotation resource references the secret.","name":"secret_rotation"},{"catch_all":false,"consulted_by":["AWS_S3_001","AWS_S3_006","AWS_S3_007","AWS_S3_010","AWS_KMS_004","AWS_SECRETSMANAGER_004","AWS_IAM_025","AWS_IAM_005","AWS_OPS_041","AWS_IAM_021"],"description":"Whether an ATTACHED AWS Organizations Resource Control Policy establishes a data perimeter for a service — a Deny on the service's actions with Resource \"*\" that is unconditional or gated only by org-membership condition keys (aws:PrincipalOrgID and friends). Such an RCP caps external/public access org-wide regardless of the resource's own policy, so the curated external-exposure findings on S3 (public access), KMS (public key policy), Secrets Manager (any-principal policy), SQS (publicly-writable-queue attack path), and STS (any-principal trust) are suppressed with a rationale. Encryption / TLS / config findings are never suppressed by this axis, and an unattached RCP suppresses nothing — as does one whose attachment a CloudFormation condition decides, since an attachment the scan cannot say gets made is not proof the guardrail is live.","name":"rcp_data_perimeter"},{"catch_all":false,"consulted_by":["AWS_EC2_001","AWS_EC2_006","AWS_IAM_023"],"description":"Whether an EC2 declarative policy (DECLARATIVE_POLICY_EC2) enforces IMDSv2 org-wide via instance_metadata_defaults http_tokens = \"required\" (or http_tokens_enforced = \"enabled\"). Declarative policies are enforced at the service control plane, so every new instance launches with IMDSv2 regardless of the resource's own metadata_options — AWS_EC2_001 / AWS_EC2_006 (IMDS hardening) and AWS_IAM_023 (IMDSv1 + privileged role SSRF chain) are suppressed with a rationale.","name":"ec2_declarative_policy"},{"catch_all":false,"consulted_by":["AWS_IAM_020","AWS_IAM_114"],"description":"Whether an ATTACHED Service Control Policy unconditionally denies (Deny, Resource \"*\", no Condition) the IAM action a privilege-escalation finding depends on. AWS_IAM_020 (generic privesc grant) is suppressed only by a service-wide iam:* / \"*\" deny; AWS_IAM_114 (PassRole-to-compute pivot) by a deny covering iam:PassRole. The rationale surfaces the SCP caveats: SCPs do not apply to the management account or to service-linked roles. An unattached SCP suppresses nothing, and neither does one whose attachment a CloudFormation condition decides — an attachment the scan cannot say gets made is not proof the guardrail is live.","name":"scp_deny_guardrail"},{"catch_all":false,"consulted_by":["AWS_CRED_003","AWS_CRED_004"],"description":"Whether a hardcoded-credential-attribute finding's value is actually a CloudFormation dynamic reference (`{{resolve:...}}`) into an encrypted secret store. `ssm-secure` and `secretsmanager` references are AWS's documented encrypted-at-rest pattern and suppress AWS_CRED_003/AWS_CRED_004 with a rationale naming the reference kind; a PLAIN `ssm` reference (unencrypted Parameter Store `String`) is deliberately NEVER suppressed — the axis keys on the reference prefix, not merely on `resolve:`-shaped text.","name":"dynamic_reference"},{"catch_all":true,"consulted_by":[],"description":"Whether a resource is CDK's own bootstrap-stack tooling (the staging S3 bucket, asset ECR repository, or deploy/exec/lookup/publishing IAM roles the `cdk-<qualifier>-<segment>-<account>-<region>` naming template identifies — or a companion of one, e.g. its inline policy / bucket policy) or the per-stack AWS::CDK::Metadata usage-telemetry resource. Both are CDK-provisioned tooling, never application infrastructure a PR author controls, so findings on them are suppressed with a rationale naming which kind of tooling resource matched.","name":"cdk_bootstrap"},{"catch_all":false,"consulted_by":["AWS_RDS_001","AWS_RDS_005"],"description":"Whether an aws_db_instance is a read replica (replicate_source_db / SourceDBInstanceIdentifier set), an Aurora cluster-member instance (engine starts with \"aurora\" AND cluster_identifier / DBClusterIdentifier set), a point-in-time restore (restore_to_point_in_time.source_dbi_resource_id / SourceDbiResourceId set), an automated-backup restore (restore_to_point_in_time.source_db_instance_automated_backups_arn / SourceDBInstanceAutomatedBackupsArn set), or a snapshot restore (snapshot_identifier / DBSnapshotIdentifier set). AWS's AWS::RDS::DBInstance reference documents StorageEncrypted as inherited from the source DB instance / automated backup / snapshot for the respective kind, and as \"not applicable\" (managed by the DB cluster) for an Aurora member; DeletionProtection carries the same cluster-managed caveat for an Aurora member but has NO such caveat for any of the other four kinds, so their own DeletionProtection still fires. AWS_RDS_001 is suppressed on all five relationship kinds; AWS_RDS_005 is suppressed ONLY on the Aurora-member kind. (SourceDBClusterIdentifier — a Multi-AZ DB cluster read-replica source — is not classified: no AWS doc states a StorageEncrypted inheritance/not-applicable claim for it, so those findings keep firing.)","name":"rds_instance_relationship"}],"engine_version":"1.18.258","mcp":{"endpoint":"/mcp","prompts":["secure-review","pre-commit-gate","secure-review-cloudformation"],"resources":["audytx://rules-catalog","audytx://context-axes","audytx://baseline-format"],"tools":["scan_terraform","scan_cloudformation","autofix_terraform","autofix_cloudformation","dry_run_autofix","dry_run_autofix_cloudformation","explain_finding","get_context_graph","cost_sampler"],"transport":"streamable-http (stateless JSON-RPC over POST)"},"module_models":10,"output_formats":["pr_comment","sarif_v2.1.0"],"rules_count":266,"service":"audytx-backend","supported_cloud":"aws","supported_event_types":["pull_request","ping"],"supported_iac":["terraform","cloudformation"]}