Insecure Communication
Detects insecure communication protocols and credential exposure in URLs
61 rules in insecure_communication.yml
CRITICAL: 12 | HIGH: 44 | MEDIUM: 5
| Rule ID | Severity | Title | Description | Refs |
|---|---|---|---|---|
consul_ | CRITICAL | HashiCorp Consul ACL default_policy=allow (Service-Mesh Open-By-Default) | A Consul config (consul.hcl, consul.json, consul agent -config-dir=) has acl { default_policy = "allow" } (or acls.default_policy: allow in YAML). With default-allow, the ACL system is effectively OFF - any client reaching 8500/tcp (HTTP API) or 8300/tcp (RPC) can read all service registrations, KV data, intentions, and node metadata. In service-mesh deployments (Consul Connect), this lets an attacker register a malicious sidecar that MitMs all mTLS traffic between services. 2024 SpecterOps research describes this as the canonical Consul-to-cluster-takeover primitive. | |
elasticsearch_ | CRITICAL | Elasticsearch xpack.security Disabled Or Bound To 0.0.0.0 | A task renders elasticsearch.yml or invokes elasticsearch-keystore/docker run elasticsearch with xpack.security.enabled: false (or unset on 8.x, where the default is true only for self-managed clusters that generate an enrollment token) AND network.host: 0.0.0.0 / network.bind_host: 0.0.0.0. Since Elastic 8.0 (Feb 2022) security is on-by-default; explicitly disabling it and binding to the public interface is the single largest cause of internet-exposed ES clusters and the Meow / ShinyHunters dump campaigns. | |
etcd_ | CRITICAL | etcd Running With client-cert-auth=false Or –insecure-transport | A task renders an etcd manifest / systemd unit / docker run quay.io/coreos/etcd with --client-cert-auth=false or --listen-client-urls=http://0.0.0.0:2379 (not https) or --insecure-transport=true. etcd is the Kubernetes control-plane’s source of truth - anyone who can speak to it bypasses the API server, RBAC, admission controllers, and audit logging. Disabling client-cert-auth effectively hands a cluster-admin kubeconfig to anyone on the network. | |
mongodb_ | CRITICAL | MongoDB Running Without Authentication On A Public Interface | A task renders mongod.conf / docker run mongo with security.authorization: disabled (or omits it while setting net.bindIp: 0.0.0.0), or starts mongod with --noauth and --bind_ip_all. This is the configuration that produced the 2017 MongoDB ransomware wave and the 2024 Meow attack resurgence (tens of thousands of exposed clusters). Even behind a firewall, running auth-disabled is an unrecoverable posture - an attacker who reaches the port has admin.system.users write. | |
mssql_ | CRITICAL | MSSQL xp_cmdshell Enabled Or sa Login Re-Activated From Playbook | A task runs sp_configure 'xp_cmdshell', 1, RECONFIGURE with show advanced options, 1, or ALTER LOGIN sa WITH PASSWORD=... ENABLE. xp_cmdshell gives any DBA (or any SQL-injection finding) an instant cmd.exe shell in the SQL Server service account’s context (usually NT SERVICE\MSSQLSERVER - a local admin on most installs). Re-enabling the sa login re-introduces the #1 lateral-movement target during ransomware campaigns (Clop/TrueBot 2023-2024 Accellion/MOVEit-adjacent targeting). | |
mysql_ | CRITICAL | MySQL SUPER/ALL Grant To Remote Host Or skip_networking Disabled With Public Bind | A task issues GRANT SUPER ... TO '...'@'%', GRANT ALL ... TO '...'@'%', or renders /etc/mysql/mysql.conf.d/mysqld.cnf / /etc/my.cnf with skip_networking=0 + bind-address=0.0.0.0 without an explicit require_secure_transport=ON. The SUPER privilege is the MySQL equivalent of sudo (bypass READ_ONLY, kill any connection, change global variables, load UDF shared objects for RCE) - granting it to '%' gives any network attacker one-step database takeover. This is the 2024 Snowflake/MOVEit credential-reuse attack pattern. | |
null_ | CRITICAL | NULL / Anonymous (ADH/eNULL/aNULL) Cipher Suite Explicitly Allowed | A TLS config (OpenSSL cipher string, Nginx ssl_ciphers, Apache SSLCipherSuite, HAProxy ssl-default-bind-ciphers, Java -Djdk.tls.disabledAlgorithms) explicitly allows NULL encryption (eNULL, NULL-MD5, NULL-SHA) or anonymous Diffie-Hellman (ADH-, AECDH-, aNULL). NULL ciphers provide AUTHENTICATION-ONLY with zero confidentiality; anonymous ciphers skip server authentication entirely and are MitM-by-design. Neither has ANY legitimate production use - they exist only in OpenSSL’s cipher tables for protocol-conformance testing. | |
oidc_ | CRITICAL | OIDC ID-Token Signature Verification Disabled Or JWKS Validation Skipped | A task sets verify_id_token: false, skip_jwks_validation: true, InsecureSkipVerify: true on an OIDC client, or passes --insecure-skip-token-verify to kube-apiserver / oidc-login. Skipping ID-token signature verification turns the entire federated-identity chain into a trust-what-you-receive primitive - any attacker who can forge an unsigned JWT (or flip the alg: none trick, CVE-2018-1000531 still actively exploited) authenticates as any user they name in the sub claim. This is MITRE T1606.001 (Web Cookies) / T1556.006 at the protocol layer. | |
postgres_ | CRITICAL | PostgreSQL pg_hba.conf Allows trust Or Legacy md5 Instead Of scram-sha-256 | A task renders /etc/postgresql/*/main/pg_hba.conf (or a pg_hba.conf under any postgres data-dir) with a host/hostssl/local line whose auth method is trust (no password at all) or md5 (cryptographically broken, rainbow-table-able). trust on any non-loopback address is the PostgreSQL equivalent of MongoDB’s --noauth; the md5 method uses a single-round MD5 of password+username and is the reason the 2024 Postgres CIS benchmark upgraded to requiring scram-sha-256 on every non-loopback row. | |
redis_ | CRITICAL | Redis Without requirepass And With protected-mode no On Public Bind | A task renders redis.conf / docker run redis without requirepass (or with a weak empty string) AND protected-mode no AND bind 0.0.0.0. Redis has no default authentication; protected-mode is the last-resort safety net that rejects external connections when auth is unconfigured. Disabling protected-mode on an exposed bind address produces the classic unauth-RCE chain via CONFIG SET dir + SLAVEOF / MODULE LOAD (Muhstik, WatchBog, P2PInfect 2024 campaigns). | |
saml_ | CRITICAL | SAML AssertionConsumerService Or OIDC Issuer URL Uses Plaintext HTTP | A task renders a SAML EntityDescriptor with AssertionConsumerService Location="http://..." / SingleLogoutService Location="http://..." OR an OIDC client/provider config with issuer: http://..., token_endpoint: http://..., jwks_uri: http://..., or authorization_endpoint: http://... (for any non-localhost host). Plaintext-HTTP federation endpoints leak the SAML assertion (containing groups + NameID + optionally emailed OTP codes) or the OIDC id_token (JWT signed, but replay-able on-path) - a passive-MITM on the login subnet immediately becomes an authentication-bypass. Required-HTTPS has been the formal baseline in both specifications since their inception and is a hard-fail on every 2024 OpenID-Federation conformance test. | |
saml_ | CRITICAL | SAML Assertion Signature Verification Disabled | A playbook configures a SAML SP (Keycloak, Shibboleth, Apache mod_auth_mellon, Python saml2, Ansible AAP SAML auth) with want_assertions_signed: false, want_response_signed: false, wantAssertionsSigned: false, or validateSignatures: false. Without signature validation, an attacker who intercepts or replays any SAML response can impersonate any user - the classic SAML-re-signing attack that has compromised several IdP-federated platforms in 2024-2025. | |
aws_ | HIGH | CloudFront Distribution Allows TLS < 1.2 (SSLv3/TLS1.0/TLS1.1 Minimum Protocol) | A community.aws.cloudfront_distribution task sets viewer_certificate.minimum_protocol_version: to SSLv3, TLSv1, TLSv1_2016, TLSv1.1_2016, or leaves it at the legacy default TLSv1. These protocols are deprecated, vulnerable to BEAST / POODLE / LOGJAM / SWEET32 downgrades, and disallowed by PCI-DSS 4.0 (eff Mar 2025), FedRAMP High, and every major compliance regime. AWS introduced TLSv1.2_2021 and TLSv1.2_2019 as the currently-approved floors; anything older should be treated as insecure. | |
aws_ | HIGH | CloudFront Cache/Default Behavior Allows HTTP (viewer_protocol_policy: allow-all) | A community.aws.cloudfront_distribution task sets default_cache_behavior.viewer_protocol_policy: allow-all or any entry in cache_behaviors.*.viewer_protocol_policy: allow-all. This allows cleartext HTTP traffic to the distribution in parallel with HTTPS, which (a) makes session cookies vulnerable to passive network capture on public Wi-Fi / transit networks, (b) permits HTTP-downgrade MITM against unpinned clients, and (c) silently serves the origin over HTTP for browsers that follow cached redirects. | |
aws_ | HIGH | ElastiCache Redis/Memcached Without In-Transit or At-Rest Encryption | A community.aws.elasticache / community.aws.elasticache_info / community.aws.elasticache_replication_group task creates a Redis or Memcached cluster with transit_encryption_enabled: false (or omitted), at_rest_encryption_enabled: false (or omitted), or neither flag present at all. Redis commands (AUTH, SET, HGETALL) travel in cleartext on the VPC network - any compromised EC2 instance or container in the same subnet can passively sniff session tokens, rate-limit counters, or application-layer secrets via tcpdump on port 6379/11211. Without at-rest encryption, an AWS operator (or a stolen backup-snapshot) can recover cached data including PII and application cache-poisoning payloads. | |
aws_ | HIGH | Elasticsearch/OpenSearch Domain Without At-Rest Encryption or HTTPS-Only | A community.aws.elasticsearch_slr / community.aws.opensearch / community.aws.elasticsearch_domain task creates a domain with encryption_at_rest.enabled: false (or missing), node_to_node_encryption.enabled: false, or domain_endpoint_options.enforce_https: false. OpenSearch (formerly Elasticsearch) domains are frequently used to index application logs, PII events, and security-event data - a single breach therefore exposes ALL historical application telemetry. Without enforce_https, HTTP clients can still hit the domain endpoint and have credentials or sensitive query parameters sniffed. | |
aws_ | HIGH | AWS OpenSearch/Elasticsearch Domain Without Node-to-Node Encryption | A community.aws.opensearch / community.aws.elasticsearch_service task creates/updates a cluster with node_to_node_encryption_options: {enabled: false} (or omits the options block - AWS default is false for Elasticsearch-5.6 and older, and the Ansible module does not force-enable it). Inter-node traffic between data, master, and UltraWarm nodes carries shard-replication, query results, and security-plugin internal API calls in cleartext over the VPC. An attacker with an ENI foothold in the same subnet (via Lambda-in-VPC compromise, Fargate exploit, or VPC-lateral-move) can sniff indexed documents including PII, access logs, and any data the application writes. | |
aws_ | HIGH | Internet-Facing ELB/ALB Listener Accepts Plain HTTP (Not HTTPS) | An amazon.aws.elb_classic_lb / community.aws.elb_application_lb task with scheme: internet-facing configures a listener using Protocol: HTTP (or protocol: http / listener.Protocol: HTTP) on a public-facing port without a companion HTTPS listener + redirect rule. All requests to the load balancer travel unencrypted over the internet. This also defeats CloudFront’s https-only / redirect-to-https viewer policy if an origin ALB still accepts HTTP. | |
aws_ | HIGH | ELB/ALB Listener Uses Deprecated SSL Negotiation Policy | An amazon.aws.elb_classic_lb / community.aws.elb_application_lb / amazon.aws.elb_network_lb task sets an HTTPS/TLS listener ssl_policy: (or policy_names:) to one of the deprecated / insecure ELB predefined policies: ELBSecurityPolicy-2015-05, ELBSecurityPolicy-TLS-1-0-2015-04, ELBSecurityPolicy-TLS-1-1-2017-01, ELBSecurityPolicy-FS-1-1-2019-08, AWSConsole-SSLNegotiationPolicy-*, Reference-Security-Policy, or any custom policy that enables DES-CBC3-SHA, RC4-, ECDHE-ECDSA-RC4-SHA, or SSLv3/TLS1.0/TLS1.1 ciphers. These expose clients to downgrade-and-MITM attacks. | |
azure_ | HIGH | Azure Database Server SSL Enforcement Disabled (ssl_enforcement/enable_ssl_enforcement: disabled) | An azure.azcollection.azure_rm_postgresqlserver / azure.azcollection.azure_rm_mysqlserver / azure.azcollection.azure_rm_mariadbserver task sets ssl_enforcement: 'Disabled' (or enforce_ssl: false / ssl_enforcement: false). Client applications can then connect over unencrypted TCP, exposing username, password, session cookies, and SQL payloads to any attacker who can reach the same Azure VNet/subnet or perform a VNet-peering MITM. Defaults-rich ODBC/JDBC drivers will happily connect unencrypted if the server allows it. | |
azure_ | HIGH | Azure Cache for Redis Accepts Plaintext on Port 6379 (enable_non_ssl_port: true) | An azure.azcollection.azure_rm_rediscache task sets enable_non_ssl_port: true (or enableNonSslPort: true). The Redis instance accepts cleartext connections on TCP 6379 in parallel with the TLS port 6380 - clients (or misconfigured libraries falling back to default port 6379) send the AUTH token and all commands unencrypted. Anyone with VNet reachability (internal attacker, compromised VM, DNS-cache-poisoning on peered VNets) can capture the auth token and full command stream. | |
azure_ | HIGH | Azure App Service Web App with HTTPS-Only Disabled (https_only: false) | An azure.azcollection.azure_rm_webapp / azure.azcollection.azure_rm_functionapp task sets https_only: false (or omits it - the App Service default allows both HTTP and HTTPS). Clients can reach the app over cleartext HTTP on the *.azurewebsites.net hostname and over any custom domain not bound with an HTTPS listener. Session cookies, bearer tokens, and form posts travel unencrypted; HSTS is not automatically applied. | |
bind_ | HIGH | BIND / PowerDNS Open Recursive Resolver On Public Interface | A task renders named.conf / named.conf.options with recursion yes; AND allow-recursion { any; } (or allow-query-cache { any; }) on a bind address that includes a public interface. Open recursive resolvers are the classic DNS amplification-attack reflectors (>50x amplification via DNSSEC-signed ANY-type queries), get your AS listed on DNS-blocklists / Shadowserver, and are the single most common abuse contributor in the 2024 Shadowserver report on exposed DNS services. | |
curl_ | HIGH | curl -k / wget –no-check-certificate In Shell Task (TLS Verification Skipped) | An ansible.builtin.shell or ansible.builtin.command task runs curl -k, curl --insecure, wget --no-check-certificate, wget --no-check-certificates, or fetch --no-verify-peer (BSD) against any URL. This disables TLS verification, turning every HTTPS fetch into a MitM-vulnerable fetch. Distinct from the existing ssl_verification_disabled rule which only catches the Ansible validate_certs: false module arg - this catches the shell-level case that Ansible can’t see. | |
dkim_ | HIGH | DKIM signing key deployed with RSA < 2048 bits or SHA-1 hash | A task deploys or configures a DKIM (DomainKeys Identified Mail) signing key as an RSA key shorter than 2048 bits, or with SHA-1 (a=rsa-sha1) instead of SHA-256 (a=rsa-sha256). RFC 8301 (2018) formally deprecated rsa-sha1 and required a minimum 2048-bit key; every major mailbox provider (Google, Microsoft 365, Yahoo, Apple iCloud, Proton) rejects or downgrades mail signed with weaker keys - BIMI and DMARC reputation are impacted. 2024 Google / Yahoo bulk-sender policy updates (Feb 2024) explicitly require 2048-bit RSA + SHA-256 for any sender over 5k msg/day. 1024-bit RSA signing keys have been factorable on commodity GPU clusters since 2022. Matches Postfix/OpenDKIM/rspamd DKIM keygen with -b 1024, DNS TXT record k=rsa; p=<short-base64>, mail_services.dkim.keysize: 1024, and AWS SES create-email-identity with KeyLength: RSA_1024_BIT. | |
dmarc_ | HIGH | DMARC record deployed with p=none (monitor-only) or missing on a production domain | A task publishes or updates a DMARC DNS TXT record (_dmarc.<domain>) with p=none (monitor-only, no enforcement) - OR a p=quarantine / p=reject record with pct= < 100 - on what is clearly a production / mail-sending domain. p=none gives zero protection against direct-domain spoofing (the #1 BEC / phishing pattern, per FBI IC3 2024 reporting $6.3B annual losses). Google, Yahoo, Apple iCloud, and Microsoft 365 (Feb 2024) now require at least p=quarantine for bulk senders; many mailbox providers downgrade reputation of any p=none sender. Also matches misconfigured records missing rua/ruf aggregate reporting, or sp=none (subdomain policy explicitly weakened below the parent). | |
exchange_ | HIGH | Mailbox inbox / transport rule configured to auto-forward externally (BEC persistence) | A task creates an Exchange Online / Microsoft 365, Google Workspace, or on-prem Exchange mailbox inbox-rule / transport-rule / Gmail-forwarding-filter that auto-forwards mail to an external (non-tenant-owned) address. This is the #1 persistence mechanism after a Microsoft 365 / Google Workspace account takeover - Mandiant M-Trends 2024 and Microsoft Digital Defense Report 2024 both list mailbox forwarding rules as the primary BEC reconnaissance and invoice-fraud persistence technique. Matches New-InboxRule -ForwardTo, Set-Mailbox -ForwardingSmtpAddress <external>, New-TransportRule -RedirectMessageTo, Graph API POST /users/{id}/mailFolders/inbox/messageRules with external forwardTo, and Google Workspace POST /admin/directory/v1/users/{u}/settings/forwardingAddresses. | |
ftp_ | HIGH | FTP with Embedded Credentials | FTP URL embeds user:password@ in the authority component. FTP transmits credentials and payload in plaintext; the URL alone is enough for a network observer to authenticate. | |
gcp_ | HIGH | GCP Cloud DNS Managed Zone with DNSSEC Disabled or Using Weak RSASHA1 Algorithm | A google.cloud.gcp_dns_managed_zone task either (a) omits dnssec_config: / sets dnssec_config.state: off, leaving the zone unsigned and spoofable via cache-poisoning attacks, or (b) configures dnssec_config.default_key_specs[].algorithm: rsasha1. RSASHA1 has been deprecated by IANA since 2012, is disallowed by NIST SP 800-57 Rev.5, and the underlying SHA-1 collision attack (SHAttered, 2017) makes forging a DNSKEY signature computationally feasible for a resourceful adversary. | |
get_ | HIGH | ansible.builtin.get_url Downloads From a Plaintext http:// URL | An ansible.builtin.get_url / get_url task uses url: http://.... The downloaded artifact (archive, binary, installer, RPM/DEB) can be modified in-flight by any on-path attacker - especially acute when the artifact is subsequently executed (e.g. mode: '0755' + a later ansible.builtin.shell invocation, or the classic dest: /tmp/install.sh + ansible.builtin.shell: bash /tmp/install.sh). Mimics the curl http://... | bash pattern this scanner already flags, but at the Ansible-module layer. | |
helm_ | HIGH | Helm Chart Repository Added Over Plaintext HTTP Or With –insecure-skip-tls-verify | A task invokes helm repo add or kubernetes.core.helm_repository with a plaintext http:// URL, or passes --insecure-skip-tls-verify / validate_certs: false. Helm chart tarballs are executable templates that can render arbitrary Kubernetes objects (including ServiceAccount tokens + RoleBinding to cluster-admin) - fetching them over HTTP allows a network-in-the-middle to swap the tarball and own the cluster on first helm install. | |
http_ | HIGH | HTTP Basic Auth in URL | HTTP URL embeds user:password@ in the authority. Plain-HTTP Basic Auth sends the base64-encoded credential on every request and is recoverable from any on-path observer. | |
istio_ | HIGH | Istio PeerAuthentication Set To PERMISSIVE (mTLS Downgrade Allowed) | A task renders an Istio PeerAuthentication / DestinationRule manifest with spec.mtls.mode: PERMISSIVE (or an empty spec.mtls: {}) in the istio-system namespace or at workload scope. PERMISSIVE mode allows plaintext traffic to co-exist with mTLS on the same port - which means any sidecar-less pod (or any attacker who gets a foothold in the cluster network) can read service-to-service traffic that the mesh was supposed to protect. The 2024 Istio security advisory explicitly calls out PERMISSIVE as a deploy-time finding that should block production rollouts. | |
kafka_ | HIGH | Kafka Listener PLAINTEXT Without SASL Or ACLs | A task renders server.properties / Strimzi KafkaUser / Helm values with listeners=PLAINTEXT://0.0.0.0:9092 AND allow.everyone.if.no.acl.found=true (or no authorizer.class.name set at all). Kafka without SASL allows any network client to produce/consume to every topic - including __consumer_offsets and __transaction_state, which an attacker can rewrite to corrupt exactly-once semantics or replay historic events (seen in 2024 Confluent-Cloud tenant-escape PoCs). | |
loki_ | HIGH | Grafana Loki auth_enabled: false Or Gateway Without X-Scope-OrgID Enforcement | A task renders a Loki config (loki-config.yaml, Helm values, or LokiStack CRD) with auth_enabled: false AND a gateway / ingress that accepts unauthenticated POSTs to /loki/api/v1/push. In multi-tenant mode Loki uses auth_enabled: true + X-Scope-OrgID header to isolate tenants; disabling auth collapses all tenants into fake and allows any caller to inject arbitrary logs (log-injection / evidence tampering) or exfiltrate logs from any tenant they can guess. Seen in 2024 Grafana Cloud tenant-escape research. | |
mongodb_ | HIGH | MongoDB $where Or mapReduce Server-Side JS With User-Templated Input | A task issues a MongoDB query via community.mongodb.mongodb_shell, pymongo.*.find, or mongosh --eval containing a $where: operator with a Jinja2-templated expression, OR a mapReduce call whose map/reduce bodies are constructed from user-supplied input ({{ item.filter }}, {{ user_query }}). $where executes arbitrary JavaScript inside the mongod process (mongod --setParameter javascriptEnabled=true default), and attacker-templated input becomes NoSQL-injection -> server-side-JS RCE. MongoDB 5.0 deprecated but did not remove $where; 7.0 disables it by default but many on-prem deploys re-enable it for legacy queries. | |
mqtt_ | HIGH | MQTT Broker Configured With allow_anonymous true | A task renders mosquitto.conf or an EMQX/HiveMQ config with allow_anonymous true (or omits password_file / JWT / OIDC bindings). MQTT brokers on the public internet with anonymous access have been weaponised to leak industrial telemetry (Shodan has ~150k exposed brokers as of 2024) and to pivot into OT networks via retained messages and Last-Will-and-Testament command injection. | |
oauth_ | HIGH | OAuth 2.0 Implicit Grant (response_type=token) Or Hybrid id_token token | A task renders application config, SPA bundle, or OIDC-client registration with response_type=token or response_type=id_token token (implicit flow / hybrid flow). The OAuth 2.0 Security Best Current Practice (RFC 8725 / OAuth 2.1 draft-16) formally deprecates the implicit grant because access tokens are delivered in the URL fragment - landing in browser history, Referer headers, and JS error-reporting payloads. Every 2024 OIDC-provider migration guide (Okta, Auth0, Entra ID) flags implicit flow as a breaking-change-required finding. | |
openssl_ | HIGH | OpenSSL FIPS Mode Disabled At Runtime (OPENSSL_FIPS=0 / fips=0 / update-crypto-policies) | A task sets OPENSSL_FIPS=0 / OPENSSL_FORCE_FIPS_MODE=0 in env, runs update-crypto-policies --set DEFAULT (RHEL/CentOS/Fedora - removes FIPS policy), update-crypto-policies --set LEGACY (even weaker - re-enables SHA-1, 3DES, DH-1024), fips-mode-setup --disable, or writes /etc/system-fips to absent. A host in FIPS mode rejects weak algorithms (MD5, SHA-1 for signatures, RC4, DES, RSA <2048, DH <2048) at the library layer - dropping out of FIPS re-enables them. FIPS 140-3 certification is required for US Federal, DoD, HIPAA, PCI-DSS (since 4.0), and many EU regulated workloads. A ‘FIPS-certified’ fleet that playbooks into non-FIPS mode fails audit and loses the cryptographic assurance the certification implies. | |
otel_ | HIGH | OpenTelemetry Collector Exporter Uses Plaintext HTTP Or insecure: true | A task renders an OpenTelemetry Collector exporters: section (or an SDK-level OTEL_EXPORTER_OTLP_ENDPOINT env-var) pointing at http://... rather than https://..., or explicitly sets tls.insecure: true. Telemetry streams contain distributed-trace HTTP headers, user IDs, IP addresses, prompt content (for LLM workloads), and SQL statements - sending them in the clear turns the telemetry pipeline itself into a passive-surveillance channel for anyone on path. The 2024 OpenTelemetry hardening guide lists TLS-everywhere as the #1 exporter requirement. | |
otel_ | HIGH | OpenTelemetry OTLP Exporter OTEL_EXPORTER_OTLP_INSECURE=true Or insecure: true (Cleartext Traces/Metrics) | A task sets OTEL_EXPORTER_OTLP_INSECURE=true, OTEL_EXPORTER_OTLP_TRACES_INSECURE=true, OTEL_EXPORTER_OTLP_METRICS_INSECURE=true, OTEL_EXPORTER_OTLP_LOGS_INSECURE=true, or renders an OTel Collector config with exporters: otlp: tls: insecure: true / insecure_skip_verify: true. OTLP traces/metrics/logs commonly contain database query strings, HTTP headers (including Authorization!), stack traces with env-var dumps, SQL parameters, and user-attribute payloads - shipping them over plaintext exposes all of this to any on-path observer. The OTel SDK defaults to gRPC-over-TLS; setting insecure=true is an explicit opt-out. Distinct from generic TLS rules because OTel has its own 5+ env vars and config keys with different regex shapes. | |
plaintext_ | HIGH | Plaintext SMTP (No TLS) | SMTP mail without TLS/SSL exposes credentials and message content on the wire | |
prometheus_ | HIGH | Prometheus remote_write Configured Without basic_auth / authorization / tls_config | A task renders a Prometheus remote_write: block whose url: is http://... OR is https://... without any of basic_auth, authorization, bearer_token_file, sigv4, or oauth2 sub-keys. Prometheus remote_write streams every scraped metric series (memory/CPU, but also application-emitted business metrics with user-IDs, feature-flag tags, and SQL-level cardinality) to the remote endpoint - an unauthenticated endpoint is a metric-exfiltration target that also accepts arbitrary pushes from any network source (Meow-attack class repeated on Mimir/Thanos receivers in 2024). | |
prometheus_ | HIGH | Prometheus Scrape Config With basic_auth Over HTTP (Cleartext Credentials Every Scrape) | A Prometheus / VictoriaMetrics / Alertmanager / Thanos scrape-config YAML has a basic_auth: block (with username:+password: or password_file:) AND the target scheme: is http (or omitted, which defaults to http). Prometheus scrapes every 15-60s - on each scrape, the Basic Auth header (base64’d user:pass) is sent in plaintext HTTP. Any on-path attacker (even transiently - a misconfigured NIC, a noisy tcpdump container, a switch-span-port) captures the credential. This is a 2024 Sysdig-reported finding present in >40% of the corporate Prometheus deployments they audited. Distinct from prometheus_scrape_no_tls (general) - this one specifically flags the HTTP+basic-auth combo as the extractable-credential anti-pattern. | |
shell_ | HIGH | shell ssh / scp / sftp Invoked With StrictHostKeyChecking=no | An ansible.builtin.shell or ansible.builtin.command task runs ssh, scp, sftp, or rsync -e ssh with -o StrictHostKeyChecking=no (or =accept-new/=off), or sets UserKnownHostsFile=/dev/null. This bypasses SSH host-identity verification and accepts whatever key the remote sends - any on-path attacker can sit between the controller and the target and read or modify every byte of the session, including private-key transfers. The existing ssh_args_disable_host_key rule only catches the Ansible ansible_ssh_common_args variable; this catches the shell-level invocation that Ansible’s SSH layer never sees. | |
sshd_ | HIGH | SSHD / Samba / Other Service Configured With Weak Ciphers (3des-cbc, arcfour, aes-cbc, hmac-md5, hmac-sha1) | A task renders a service config (/etc/ssh/sshd_config, /etc/ssh/ssh_config, smb.conf, krb5.conf) with Ciphers, MACs, KexAlgorithms, or HostKeyAlgorithms lines containing legacy weak primitives: 3des-cbc (Sweet32 birthday attack), arcfour* / RC4 (bias attacks, removed 2015), aes128-cbc / aes256-cbc (plaintext-oracle attacks in CBC mode), hmac-md5* (chosen-prefix collisions), hmac-sha1 (SHAttered 2017), diffie-hellman-group1-sha1 (Logjam 1024-bit), ssh-dss (deprecated). Modern OpenSSH (≥9.0) has the safe defaults built-in - explicit Ciphers / MACs lines almost always ADD legacy support for ‘some old device’ and weaken the server. The 2024 CISA SSH-hardening guidance and NIST SP 800-52r2 explicitly ban these. Distinct from sshd_ciphers rule covering TLS-level (if any such rule exists); this catches the SSH + Kerberos + SMB variants comprehensively. | |
ssl_ | HIGH | SSL Verification Disabled | verify_ssl / ssl_verify / check_ssl / validate_certs is set to false/no/0. Disabling cert validation defeats TLS’s identity guarantee and reduces transport security to encryption alone. | |
telnet_ | HIGH | Telnet Protocol Usage | Telnet transmits data (including credentials) in plaintext; use SSH instead | |
tls_ | HIGH | TLS 1.0 / 1.1 Explicitly Enabled In Server Config | A rendered web-server / app-server / load-balancer config (nginx, Apache httpd, HAProxy, Envoy, Traefik, Tomcat, IIS) has ssl_protocols, SSLProtocol, tls-min-version, or tls_versions explicitly including TLSv1, TLSv1.0, TLSv1.1, tlsv1.0, or tlsv1.1. Both TLS 1.0 and 1.1 have been formally deprecated by IETF RFC 8996 (2021) - they retain BEAST, POODLE, and Lucky13 attack surface. PCI-DSS v4 (effective 2024-03), HIPAA security guidance, FedRAMP Rev5, and CIS v8 all require TLS 1.2+ as a mandatory baseline. | |
tls_ | HIGH | Web/proxy server TLS min version configured below 1.2 (TLSv1.0 or 1.1 enabled) | A task renders an nginx / Apache httpd / HAProxy / Envoy config with an explicit TLSv1 / TLSv1.1 protocol directive (ssl_protocols TLSv1 TLSv1.1 TLSv1.2, SSLProtocol +TLSv1 +TLSv1.1, ssl-min-ver TLSv1.0, tls_minimum_protocol_version: TLSv1_1). TLS 1.0 and 1.1 have been deprecated by IETF RFC 8996 (March 2021), disabled by default in all major browsers since 2020, removed from FIPS 140-3, and are an automatic PCI-DSS 4.0 audit failure. Legacy re-enablement is usually ‘we have a compatibility test that broke’ - which almost always means an old IoT device that itself needs to be retired, not TLS weakened for. | |
tls_ | HIGH | TLS cipher-suite config enables RC4 / 3DES / NULL / EXPORT / DES / MD5 | A task renders a TLS cipher-suite config that explicitly allows RC4, 3DES (SWEET32/CVE-2016-2183), NULL (no encryption), EXPORT (40/56-bit), DES, aNULL, eNULL, or MD5-based suites. Matches nginx (ssl_ciphers), Apache (SSLCipherSuite), HAProxy (ssl-default-bind-ciphers), OpenSSL (openssl_cipher_list), Envoy (cipher_suites:), and Kubernetes Ingress (nginx.ingress.kubernetes.io/ssl-ciphers). The presence of :RC4: or :DES: / :3DES: in a cipher string is an automatic PCI-DSS 4.0 failure and a CVSS-9+ finding in any modern pentest. | |
unencrypted_ | HIGH | Unencrypted Database Connection | Database URL pins sslmode=disable or ssl=false. Unencrypted DB connections expose credentials and rows on the wire and fail HIPAA/PCI transit-encryption requirements. | |
uri_ | HIGH | ansible.builtin.uri Calls a Plaintext http:// URL | An ansible.builtin.uri / uri task passes a url: starting with http:// (not https://). Headers, bearer tokens, query-string parameters, and POST bodies travel in the clear across whatever network path the Ansible control node traverses - increasingly public WiFi/VPN hops in remote-work contexts. Attackers with packet-capture capability intercept the request, replay it, or inject responses (for GET calls that feed into register: downstream-logic, an injected response can pivot the playbook into arbitrary-command execution via Jinja2 template evaluation). | |
uri_ | HIGH | ansible.builtin.uri With validate_certs: false (Disables TLS Certificate Validation) | An ansible.builtin.uri / uri task sets validate_certs: false. Every HTTPS request issued by the module proceeds even when the peer’s TLS certificate is expired, self-signed, hostname-mismatched, or signed by a chain the system doesn’t trust. Any on-path attacker can present their own certificate and the Ansible control node will POST credentials, tokens, secret-values, or PII directly to them. This is the #1 source of credential leakage in Ansible-driven CI pipelines (2023 GitLab-CI data showed 38% of uri: tasks in public repos had this misconfiguration). | |
weak_ | HIGH | openssl dhparam Generated With Key Size < 2048 Bits | A task runs openssl dhparam -out <file> 512 or 1024 (or passes bit-length ≤ 1024 to a community.crypto.openssl_dhparam module call). DH parameters smaller than 2048 bits are trivially broken by the Logjam attack (2015, precompute for common primes) and by any well-funded state actor in real time. RFC 7919 standardizes FFDHE named groups at 2048/3072/4096. Using pre-2015 2048 or anything ≤1024 is unambiguously a regression. | |
weak_ | HIGH | openssl genrsa / community.crypto.openssl_privatekey Generated Below 2048 Bits | A task runs openssl genrsa -out <file> 512|1024 or configures community.crypto.openssl_privatekey with size: 512|1024. RSA-1024 has been deprecated for server certificates by CA/Browser Forum since 2013; NIST SP 800-131A disallows ≤1024 for anything after 2014. Modern CAs (Let’s Encrypt, DigiCert, GlobalSign) REJECT CSRs with <2048-bit RSA keys. Generating a 1024-bit key today guarantees either a self-signed deployment or a hidden internal-CA workaround - both operationally broken. | |
aws_ | MEDIUM | CloudFront Distribution Uses Default *.cloudfront.net Certificate (cloudfront_default_certificate: true) | A community.aws.cloudfront_distribution task has viewer_certificate.cloudfront_default_certificate: true (or omits a custom acm_certificate_arn: / iam_certificate_id:). The distribution will serve TLS with CloudFront’s default wildcard *.cloudfront.net cert, which (a) forces clients to either ignore the SAN mismatch for your custom domain or accept generic CF branding, (b) precludes any SNI-based access-control via viewer_certificate.ssl_support_method: sni-only, and (c) commonly correlates with origin configurations that fall back to HTTP-only, defeating end-to-end TLS. | |
aws_ | MEDIUM | Kinesis Data Stream Without Server-Side Encryption | A community.aws.kinesis_stream task sets encryption_type: NONE (or omits encryption_type: + key_id:). Records flowing through the stream - which typically include application event-bus messages, IoT telemetry, CDC change-data-capture rows, or clickstream sessions - land in Kinesis storage unencrypted. Anyone with kinesis:GetRecords + kinesis:GetShardIterator on the stream can read the cleartext history; there is no defense-in-depth KMS envelope. | |
aws_ | MEDIUM | AWS SQS Queue Without Server-Side KMS Encryption (kms_master_key_id missing) | A community.aws.sqs_queue task creates/updates an SQS queue without kms_master_key_id: (or sqs_managed_sse_enabled: true). AWS SQS without SSE stores messages in plaintext on the SQS service substrate. Sensitive payloads (JSON fanouts containing PII, internal auth tokens, SAML assertions, workflow state) are readable by any AWS support operator with substrate-level access and to anyone who exfiltrates an SQS poll credential. SSE-KMS also enables per-queue key-rotation, queue-level revocation, and CloudTrail visibility on KMS Decrypt calls - critical forensic telemetry. | |
insecure_ | MEDIUM | Insecure Protocol Usage | An Ansible task value (url, dest, repo, src) references http://, ftp://, telnet://, tftp://, or rsync:// for content that is not signature-validated. None of these schemes encrypt traffic; tftp and rsync (the rsync:// daemon protocol, not rsync-over-ssh) additionally have no built-in authentication. URLs inside comments, license headers, doc text, and apt_key:/apt_repository: invocations (which are GPG-validated by the package manager) are filtered out post-match. | |
weak_ | MEDIUM | Weak Cipher Suite | ssl_cipher / cipher_suite includes RC4, DES, MD5, or SHA1. These primitives are broken or deprecated and trip PCI-DSS, FedRAMP, and most modern cipher policies. |