rastray 0.15.0

Blazing-fast static analysis CLI for security, dependency, and performance audits.
# RSTR-NET-005 — Java HostnameVerifier accepts every hostname

## Summary

A Java program installs a custom `HostnameVerifier` whose `verify(...)`
method (or lambda body) returns `true` unconditionally. The result:
TLS still negotiates a session and validates the server certificate
chain, but the **hostname binding step** — confirming that the
certificate was actually issued for the host you intended to talk to
— is skipped. An attacker on the network path who can present *any*
valid certificate (even for a different hostname) terminates your
TLS connection and reads / modifies the traffic.

This is one of the two classic "we just want it to work, ship it"
TLS bypasses (the other is trusting all certs in a custom
`X509TrustManager`). It's particularly dangerous in mobile and
backend contexts where the application talks to a fixed
production hostname — disabling hostname verification gives every
person on a coffee-shop wifi a working MITM.

## Severity

`High`.

## Languages

Java, Kotlin (`.java`, `.kt`, `.kts`).

## What rastray flags

Lambda form:

```java
conn.setHostnameVerifier((hostname, session) -> true);              // ← flagged
```

Anonymous-inner-class form:

```java
conn.setHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;                                                // ← flagged
    }
});
```

## What rastray deliberately does *not* flag

A verifier that consults an allow-list:

```java
conn.setHostnameVerifier((hostname, session) -> ALLOWED_HOSTS.contains(hostname));
```

Or one that delegates to the JDK default after a guard:

```java
HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
conn.setHostnameVerifier((hostname, session) ->
    INTERNAL_HOSTS.contains(hostname) || defaultVerifier.verify(hostname, session));
```

## How to fix it

The simplest answer: **delete the custom verifier**. The JDK default
verifier checks the certificate's `subjectAlternativeName` against
the hostname you connected to, which is the correct behaviour for
99% of cases. Only override if you have a specific reason
(self-signed cert pinned by hash, internal CA, on-device
certificate-pinning library).

If overriding is genuinely needed:

```java
conn.setHostnameVerifier((hostname, session) -> {
    if (!ALLOWED_HOSTS.contains(hostname)) {
        return false;
    }
    return HttpsURLConnection.getDefaultHostnameVerifier()
        .verify(hostname, session);
});
```

For HTTP clients that wrap `URLConnection` (OkHttp, Retrofit), use
the framework's hostname-verifier hook rather than reaching into the
underlying connection.

## How to suppress

If the verifier is intentionally permissive in a test-only context
(e.g. integration tests against a self-signed local server),
suppress per-line:

```java
// rastray-ignore: RSTR-NET-005 — local integration test only, never compiled into release builds
conn.setHostnameVerifier((hostname, session) -> true);
```

Or scope the rule to non-test files in `.rastray.toml`.

## References

- [OWASP — Testing for Weak Transport Layer Security]https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/01-Testing_for_Weak_Transport_Layer_Security
- [SEI CERT Java MSC03-J]https://wiki.sei.cmu.edu/confluence/display/java/MSC03-J.+Never+hard+code+sensitive+information
- [CWE-295 — Improper Certificate Validation]https://cwe.mitre.org/data/definitions/295.html
- [CWE-297 — Improper Validation of Certificate with Host Mismatch]https://cwe.mitre.org/data/definitions/297.html