VNX-SEC-017 – Plaintext Protocol URL

Overview

This rule detects connection URLs using unencrypted protocol schemes — redis://, amqp://, ftp://, telnet://, and ldap:// — in source files. These protocols transmit all data, including authentication credentials, in cleartext. Anyone with the ability to observe network traffic between your application and the target service can intercept passwords, read data payloads, and replay or modify messages. Each of these protocols has a secure TLS-wrapped equivalent that should be used instead.

Severity: Medium | CWE: CWE-319 – Cleartext Transmission of Sensitive Information

Why This Matters

The assumption that internal network traffic is “safe” from interception has been repeatedly invalidated. Cloud environments, microservice meshes, and containerised workloads share physical and virtual network infrastructure. A compromised container, a misconfigured cloud security group, or a lateral-movement foothold can put an attacker in a position to sniff internal traffic. Technologies like ARP spoofing, BGP hijacking, and compromised network devices have all been used to intercept “internal” traffic.

Specific protocol risks:

  • redis:// — Redis AUTH passwords transmitted in plaintext; session data or queue contents readable
  • amqp:// — RabbitMQ credentials and message payloads exposed; business logic data readable
  • ftp:// — Username, password, and file contents all transmitted in cleartext; replaced by FTPS or SFTP
  • telnet:// — All terminal input including passwords transmitted in cleartext; replaced by SSH
  • ldap:// — Directory queries and BIND credentials (usernames/passwords) transmitted in cleartext; replaced by LDAPS

OWASP ASVS v4 requirement V9.1.1 mandates that all communications use TLS, and V9.1.2 prohibits fallback to plaintext protocols. Cleartext protocol use is also a violation of PCI DSS Requirement 4.2 (never send unprotected card data over open public networks) and HIPAA’s Technical Safeguard for encryption in transit (45 CFR § 164.312(e)(2)(ii)).

What Gets Flagged

# FLAGGED: plaintext Redis connection
import redis

r = redis.from_url("redis://user:password@redis.example.com:6379/0")
# FLAGGED: plaintext AMQP (RabbitMQ) connection
import pika

params = pika.URLParameters("amqp://guest:guest@rabbitmq.example.com:5672/")
connection = pika.BlockingConnection(params)
# FLAGGED: LDAP without TLS in config
auth:
  ldap_url: "ldap://ldap.corp.example.com:389"
# FLAGGED: FTP in a CI script
ftp://deploy:secret@files.example.com/releases/app.tar.gz

Note: lock files (.lock, .sum) and minified assets (.min.js) are excluded from analysis.

Remediation

Replace each plaintext protocol with its TLS-encrypted equivalent:

PlaintextEncryptedNotes
redis://rediss://Note the double s
amqp://amqps://RabbitMQ supports TLS natively
ftp://ftps:// or sftp://Prefer SFTP (SSH-based)
telnet://ssh://Telnet is completely obsolete
ldap://ldaps://Or use LDAP+STARTTLS
# SAFE: encrypted Redis connection
import redis, os

r = redis.from_url("rediss://user:password@redis.example.com:6380/0")
# Or use SSL parameters, loading credentials from the environment
r = redis.Redis(
    host=os.environ['REDIS_HOST'],
    port=6380,
    password=os.environ['REDIS_PASSWORD'],
    ssl=True,
    ssl_cert_reqs='required',
)
# SAFE: encrypted AMQP connection (RabbitMQ with TLS)
import pika, ssl

ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations('/etc/ssl/certs/ca-certificates.crt')

params = pika.URLParameters("amqps://user:pass@rabbitmq.example.com:5671/")
connection = pika.BlockingConnection(params)
# SAFE: LDAPS in config
auth:
  ldap_url: "ldaps://ldap.corp.example.com:636"

For legacy systems that do not support TLS natively, use stunnel as a TLS proxy to wrap the connection without modifying the application:

# stunnel.conf — wrap Redis in TLS
[redis-tls]
client = yes
accept = 127.0.0.1:6379
connect = redis.example.com:6380

The application then connects to redis://127.0.0.1:6379 locally, and stunnel handles TLS to the actual server.

Load connection URLs from environment variables so that switching between environments does not require code changes:

# SAFE: URL from environment variable — use rediss:// in the secret
import os, redis

r = redis.from_url(os.environ['REDIS_URL'])

Prevent future regressions with pre-commit secret scanning tools:

# Install detect-secrets and scan for plaintext protocol URLs
pip install detect-secrets
detect-secrets scan --list-all-plugins

# Or use git-secrets with a custom pattern
git secrets --add 'redis://[a-zA-Z0-9]'
git secrets --add 'amqp://[a-zA-Z0-9]'
git secrets --add 'ldap://[a-zA-Z0-9]'

References