# GO-NET-001: HTTP Server Without TLS

> **Severity:** HIGH | **CWE:** CWE-319 | **OWASP:** A02:2021

- **Language:** Go
- **Category:** Security
- **URL:** https://codepathfinder.dev/registry/golang/security/GO-NET-001
- **Detection:** `pathfinder scan --ruleset golang/GO-NET-001 --project .`

## Description

`http.ListenAndServe()` starts an HTTP server without TLS encryption. All transmitted
data — login credentials, session cookies, API keys, personal information, financial
data, and application payloads — travels in plaintext over the network and can be read
or modified by any network observer on the path between client and server.

**Threat model**:
- "**Same network (Wi-Fi, corporate LAN)**: Any device on the same network can passively"
  capture all HTTP traffic using standard tools (Wireshark, tcpdump). Coffee shop Wi-Fi,
  shared office networks, and corporate LANs are all attacked this way.
- "**Network infrastructure**: ISPs, VPN providers, and enterprise proxies can inspect"
  and modify HTTP traffic in transit.
- "**MITM attacks**: ARP poisoning, rogue Wi-Fi access points, and BGP hijacking can"
  redirect HTTP traffic through attacker-controlled infrastructure.

**Cookie theft**: Session cookies transmitted over HTTP can be stolen and used to
hijack authenticated sessions without knowing the user's password. The `Secure`
cookie flag instructs browsers to only send cookies over HTTPS — but the flag is
meaningless if the server itself doesn't use HTTPS.

**HTTP Strict Transport Security (HSTS)**: Requires TLS to be configured first.
HSTS tells browsers to always use HTTPS for a domain for a specified duration.
`http.ListenAndServe()` cannot benefit from HSTS.

**When HTTP (non-TLS) is acceptable**:
- Internal health check endpoints binding to `localhost` or `127.0.0.1` only.
- When TLS is terminated at a load balancer or reverse proxy (nginx, Caddy, AWS ALB)
  and the connection from LB to server is on a trusted private network or localhost.
- Development servers that never handle real user data.

**Modern alternatives for TLS in Go**:
- `http.ListenAndServeTLS(addr, certFile, keyFile, handler)` — standard TLS
- `golang.org/x/crypto/acme/autocert` — automatic Let's Encrypt certificate management
- Caddy web server with reverse proxy — automatic HTTPS with zero configuration
- **crypto/tls** with `tls.NewListener` for fine-grained TLS control


## Vulnerable Code

```python
# --- file: vulnerable.go ---
// GO-NET-001 positive test cases — all SHOULD be detected
package main

import "net/http"

func insecureHTTPServer() {
	mux := http.NewServeMux()
	// SINK: plaintext HTTP — credentials exposed to network
	http.ListenAndServe(":8080", mux)
}

func insecureHTTPServerNilHandler() {
	// SINK: nil handler uses DefaultServeMux
	http.ListenAndServe(":9090", nil)
}

# --- file: go.mod ---
module example.com/go-net-001/positive

go 1.21

# --- file: go.sum ---

```

## Secure Code

```python
// SECURE: HTTPS with explicit TLS certificate files
func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", mux))
}

// SECURE: TLS with custom configuration (TLS 1.2+ required, strong cipher suites)
func main() {
    tlsConfig := &tls.Config{
        MinVersion: tls.VersionTLS12,
        CurvePreferences: []tls.CurveID{
            tls.CurveP256,
            tls.X25519,
        },
    }
    srv := &http.Server{
        Addr:      ":443",
        Handler:   myHandler,
        TLSConfig: tlsConfig,
    }
    log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
}

// SECURE: automatic TLS with Let's Encrypt (golang.org/x/crypto/acme/autocert)
import "golang.org/x/crypto/acme/autocert"

func main() {
    m := &autocert.Manager{
        Prompt:     autocert.AcceptTOS,
        HostPolicy: autocert.HostWhitelist("example.com", "www.example.com"),
        Cache:      autocert.DirCache("/var/cache/autocert"),
    }
    srv := &http.Server{
        Addr:      ":443",
        Handler:   myHandler,
        TLSConfig: m.TLSConfig(),
    }
    // Redirect HTTP to HTTPS
    go http.ListenAndServe(":80", m.HTTPHandler(nil))
    log.Fatal(srv.ListenAndServeTLS("", ""))
}

// ACCEPTABLE: HTTP for localhost health checks only
func main() {
    // External: HTTPS on :443
    go log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", appHandler))
    // Internal: HTTP on localhost only for health check
    healthMux := http.NewServeMux()
    healthMux.HandleFunc("/health", healthHandler)
    log.Fatal(http.ListenAndServe("127.0.0.1:8081", healthMux)) // localhost only
}

```

## Detection Rule (Python SDK)

```python
"""GO-NET-001: HTTP server started without TLS (http.ListenAndServe)."""

from codepathfinder.go_rule import QueryType
from codepathfinder import flows
from codepathfinder.go_decorators import go_rule


class GoHTTPServer(QueryType):
    fqns = ["net/http"]
    patterns = ["http.*"]
    match_subclasses = False


@go_rule(
    id="GO-NET-001",
    severity="HIGH",
    cwe="CWE-319",
    owasp="A02:2021",
    tags="go,security,tls,http,cleartext,CWE-319,OWASP-A02",
    message=(
        "Detected http.ListenAndServe() starting an HTTP server without TLS. "
        "All data transmitted over HTTP is unencrypted and can be intercepted "
        "by network observers (man-in-the-middle attacks). "
        "Use http.ListenAndServeTLS(addr, certFile, keyFile, handler) instead."
    ),
)
def detect_http_without_tls():
    """Detect HTTP server started without TLS (http.ListenAndServe)."""
    return GoHTTPServer.method("ListenAndServe")
```

## How to Fix

- Use http.ListenAndServeTLS() with a valid certificate for all externally accessible servers.
- For automatic certificate management, use golang.org/x/crypto/acme/autocert (Let's Encrypt).
- Set TLSConfig.MinVersion to tls.VersionTLS12 or tls.VersionTLS13.
- Add HTTP Strict Transport Security (HSTS) header with a long max-age.
- Set secure cookie flags: `Secure: true, HttpOnly: true, SameSite: http.SameSiteLaxMode`.
- http.ListenAndServe is acceptable only on loopback (127.0.0.1) for internal health checks.

## Security Implications

- **Session Hijacking:** Session cookies transmitted over HTTP are visible to any network observer.
An attacker who intercepts the `Set-Cookie: session_id=abc123` header can replay
that cookie to impersonate the user for the lifetime of the session.

- **Credential Interception:** Login forms that POST over HTTP send username and password in plaintext. The
HTTP POST body is fully readable in tcpdump/Wireshark captures without any
decryption.

- **Traffic Modification (Active MITM):** An active MITM attacker can inject JavaScript into HTTP responses to install
persistent XSS payloads, steal future requests, or redirect users to phishing sites.

- **Downgrade Attacks:** Without HSTS, browsers may follow links to the HTTP version of a site even if
HTTPS exists. Attackers on the network can respond to HTTP requests before the
HTTPS redirect reaches the user (SSL stripping attack).


## References

- [CWE-319: Cleartext Transmission of Sensitive Information — MITRE](https://cwe.mitre.org/data/definitions/319.html)
- [Go net/http ListenAndServeTLS documentation](https://pkg.go.dev/net/http#ListenAndServeTLS)
- [Go golang.org/x/crypto/acme/autocert (Let's Encrypt)](https://pkg.go.dev/golang.org/x/crypto/acme/autocert)
- [OWASP Transport Layer Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html)
- [OWASP TLS Cipher String Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html)
- [HSTS — HTTP Strict Transport Security (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
- [Let's Encrypt — Free TLS Certificates](https://letsencrypt.org/docs/)

---

Source: https://codepathfinder.dev/registry/golang/security/GO-NET-001
Code Pathfinder — Open source, type-aware SAST with cross-file dataflow analysis
