problem-based-packs.insecure-transport.java-spring.spring-ftp-request.spring-ftp-request

profile photo of semgrepsemgrep
Author
6,272
Download Count*

Checks for outgoing connections to ftp servers via Spring plugin ftpSessionFactory. FTP does not encrypt traffic, possibly leading to PII being sent plaintext over the network.

Run Locally

Run in CI

Defintion

rules:
  - id: spring-ftp-request
    message: Checks for outgoing connections to ftp servers via Spring plugin
      ftpSessionFactory. FTP does not encrypt traffic, possibly leading to PII
      being sent plaintext over the network.
    severity: WARNING
    metadata:
      likelihood: MEDIUM
      impact: MEDIUM
      confidence: MEDIUM
      category: security
      cwe: "CWE-319: Cleartext Transmission of Sensitive Information"
      owasp: A03:2017 - Sensitive Data Exposure
      references:
        - https://docs.spring.io/spring-integration/api/org/springframework/integration/ftp/session/AbstractFtpSessionFactory.html#setClientMode-int-
      subcategory:
        - vuln
      technology:
        - spring
      vulnerability: Insecure Transport
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Mishandled Sensitive Information
    languages:
      - java
    fix-regex:
      regex: "[fF][tT][pP]://"
      replacement: sftp://
      count: 1
    pattern-either:
      - pattern: |
          $SF = new DefaultFtpSessionFactory(...);
          ...
          $SF.setHost("=~/^[fF][tT][pP]://.*/");
          ...
          $SF.$FUNC(...);
      - pattern: |
          $SF = new DefaultFtpSessionFactory(...);
          ...
          String $URL = "=~/^[fF][tT][pP]://.*/";
          ...
          $SF.setHost($URL);
          ...
          $SF.$FUNC(...);

Examples

spring-ftp-request.java

class Bad {
    @Bean
    @ConditionalOnMissingBean
    public SessionFactory<FTPFile> bad1(FtpSessionFactoryProperties properties) {
        // ruleid: spring-ftp-request
        DefaultFtpSessionFactory ftpSessionFactory = new DefaultFtpSessionFactory();
        ftpSessionFactory.setHost("ftp://example.com");
        ftpSessionFactory.setPort(properties.getPort());
        ftpSessionFactory.setUsername(properties.getUsername());
        ftpSessionFactory.setPassword(properties.getPassword());
        ftpSessionFactory.setClientMode(properties.getClientMode().getMode());
        if (properties.getCacheSessions() != null) {
            CachingSessionFactory<FTPFile> csf = new CachingSessionFactory<>(ftpSessionFactory);
            return csf;
        }
        else {
            return ftpSessionFactory;
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public SessionFactory<FTPFile> bad2(FtpSessionFactoryProperties properties) {
        // ruleid: spring-ftp-request
        DefaultFtpSessionFactory ftpSessionFactory = new DefaultFtpSessionFactory();
        String url = "ftp://example.com";
        ftpSessionFactory.setHost(url);
        ftpSessionFactory.setPort(properties.getPort());
        ftpSessionFactory.setUsername(properties.getUsername());
        ftpSessionFactory.setPassword(properties.getPassword());
        ftpSessionFactory.setClientMode(properties.getClientMode().getMode());
        if (properties.getCacheSessions() != null) {
            CachingSessionFactory<FTPFile> csf = new CachingSessionFactory<>(ftpSessionFactory);
            return csf;
        }
        else {
            return ftpSessionFactory;
        }
    }
}

class Ok {
    @Bean
    @ConditionalOnMissingBean
    public SessionFactory<FTPFile> ok1(FtpSessionFactoryProperties properties) {
        // ok: spring-ftp-request
        DefaultFtpSessionFactory ftpSessionFactory = new DefaultFtpSessionFactory();
        ftpSessionFactory.setHost("sftp://example.com");
        ftpSessionFactory.setPort(properties.getPort());
        ftpSessionFactory.setUsername(properties.getUsername());
        ftpSessionFactory.setPassword(properties.getPassword());
        ftpSessionFactory.setClientMode(properties.getClientMode().getMode());
        if (properties.getCacheSessions() != null) {
            CachingSessionFactory<FTPFile> csf = new CachingSessionFactory<>(ftpSessionFactory);
            return csf;
        }
        else {
            return ftpSessionFactory;
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public SessionFactory<FTPFile> ok2(FtpSessionFactoryProperties properties) {
        // ok: spring-ftp-request
        DefaultFtpSessionFactory ftpSessionFactory = new DefaultFtpSessionFactory();
        String url = "sftp://example.com";
        ftpSessionFactory.setHost(url);
        ftpSessionFactory.setPort(properties.getPort());
        ftpSessionFactory.setUsername(properties.getUsername());
        ftpSessionFactory.setPassword(properties.getPassword());
        ftpSessionFactory.setClientMode(properties.getClientMode().getMode());
        if (properties.getCacheSessions() != null) {
            CachingSessionFactory<FTPFile> csf = new CachingSessionFactory<>(ftpSessionFactory);
            return csf;
        }
        else {
            return ftpSessionFactory;
        }
    }
}