Use of an insecure channel

Need

Secure transmission of sensitive information

Context

• Usage of Rust 1.75+ for building application services

• Usage of the lettre crate for sending SMTP email

• Usage of the suppaftp crate for FTP and FTPS connections

Description

1. Non compliant code

use ftp::FtpStream;
use lettre::transport::smtp::SmtpTransport;
use telnet::Telnet;

fn main() {
    // Plaintext FTP (port 21)
    let _ftp = FtpStream::connect("ftp.example.com:21").unwrap();
    // Plaintext SMTP (no TLS)...

The code below opens application traffic over three plaintext protocols. `FtpStream::connect("ftp.example.com:21")` from the `ftp` crate speaks the unencrypted FTP control channel on port 21. Both the login credentials (USER/PASS commands) and the transferred files travel in cleartext, so anyone on the network path can capture them. `SmtpTransport::builder_dangerous("mail.example.com").build()` is the explicit opt-out in `lettre` for any TLS protection — the resulting transport will deliver SMTP commands (including AUTH PLAIN/LOGIN) and message bodies in cleartext. `Telnet::connect(("host.example.com", 23), 256)` opens a Telnet session, which sends every keystroke (including the login prompt) as raw bytes on the wire. An attacker performing a man-in-the-middle attack on the local network — or any intermediate hop — can read or alter these connections, steal credentials, and forge requests.

2. Steps

• Replace plaintext FTP (`ftp` crate, port 21) with FTPS via `suppaftp::FtpStream::into_secure` using a `native-tls` or `rustls` connector, and connect on port 990 or upgrade from 21 with explicit FTPS.

• Replace `SmtpTransport::builder_dangerous(host).build()` with `SmtpTransport::relay(host).unwrap().build()` (or `SmtpTransport::starttls_relay(host)`) so `lettre` enforces TLS on every SMTP session.

• Remove all Telnet usage and replace it with SSH over an authenticated crate such as `ssh2` or `russh`; never expose a Telnet listener.

• Pin the TLS configuration to TLS 1.2 or higher and verify the server certificate against a trusted root store; reject self-signed certificates outside of explicit, audited development paths.

• Add a network-egress test (or an integration test against a sandbox server) that fails the build if any traffic is observed on ports 21, 23, or 25 without a TLS upgrade.

3. Secure code example

use lettre::transport::smtp::SmtpTransport;
use suppaftp::{native_tls::TlsConnector, FtpStream};

fn main() {
    // FTPS over TLS
    let ftp = FtpStream::connect("ftp.example.com:21").unwrap();
    let _ftps = ftp
        .into_secure(TlsConnector::new().unwrap().into(), "ftp.example.com")...

The corrected code replaces every plaintext channel with its TLS-secured counterpart. `suppaftp::FtpStream::connect(...).into_secure(...)` upgrades the FTP connection to FTPS using `native-tls`, so credentials and file payloads are wrapped in a verified TLS session before they leave the host. `SmtpTransport::relay("mail.example.com").unwrap().build()` is the canonical `lettre` constructor: unlike `builder_dangerous`, `relay` mandates a TLS-protected SMTP transport (either implicit TLS on port 465 or STARTTLS on 587). The Telnet client is removed entirely. There is no secure variant of Telnet; remote shell access must be performed over SSH (for example via the `ssh2` or `russh` crates), which authenticates the server's host key and encrypts the entire session. With these changes, credentials and payload data are always wrapped in an authenticated TLS session, neutralizing passive eavesdropping and active man-in-the-middle attacks on the network path.