Skip to main content
interlace
Plugin: browser-securityRules

no-unencrypted-transmission

Detects unencrypted data transmission (HTTP vs HTTPS, plain text protocols)

CWE: CWE-693
OWASP Mobile: OWASP Mobile Top 10

Detects unencrypted data transmission (HTTP vs HTTPS, plain text protocols). This rule is part of eslint-plugin-browser-security and provides LLM-optimized error messages that AI assistants can automatically fix.

💼 This rule is set to error by default in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-319 (Cleartext Transmission of Sensitive Information)
SeverityHIGH (security vulnerability)
Auto-Fix💡 Suggestion (rewrites the scheme to its TLS twin, string literals only)
CategorySecurity
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForAll applications making network requests, APIs, database connections

Vulnerability and Risk

Vulnerability: Transmission of sensitive data over unencrypted protocols (HTTP) allows unauthorized parties to intercept or modify the data in transit.

Risk: Man-in-the-Middle (MitM) attacks can capture sensitive information like authentication tokens, passwords, or personal data. Attackers can also inject malicious content into the response.

Detection Flow

Why This Matters

IssueImpactSolution
🔒 Man-in-MiddleData intercepted in transitUse HTTPS/TLS
🔐 Data BreachSensitive data exposedEncrypt all transmissions
🍪 ComplianceViolates security standardsEnforce encrypted protocols
📊 Best PracticeAll external connections need TLSUse secure protocols

Detection Patterns

By default the rule detects the cleartext non-web protocols, in a string literal or in the static text of a template literal:

  • FTP: ftp:// (should use ftps:// / sftp://)
  • TCP: tcp://
  • MongoDB: mongodb:// (should use mongodb+srv:// or TLS)
  • Redis: redis:// (should use rediss://)
  • MySQL: mysql:// (should use SSL)

http:// and ws:// are not in the defaults. They are owned by the transport partition, so each line draws one finding:

ShapeOwner
URL argument of fetch / axios.<verb>require-https-only
http:// in a subresource positiondetect-mixed-content
any other hardcoded http:// URLno-http-urls
URL argument of new WebSocket(…)require-websocket-wss
any other ws:// URLno-insecure-websocket

Add them back with insecureProtocols if you run this rule without those siblings.

A loopback host on a web scheme, an RFC 2606 reserved domain, an XML namespace URI and a string being tested for its scheme are never reported. On the non-web schemes loopback is not exempt by default — a mongodb://user:pass@localhost string carries credentials that survive a host swap.

allowInTests exempts, in test files only, URLs whose written-down host is loopback (redis://localhost:6379, `mongodb://127.0.0.1/${db}`) on any scheme, and templates whose host is left to an interpolation. A real host in a test file still reports.

Examples

❌ Incorrect

// Unencrypted transmission
const mongoUrl = 'mongodb://localhost:27017/db'; // ❌ MongoDB without encryption

const mongoProd = `mongodb://db.internal:27017/${name}`; // ❌ template, fixed scheme

const redisUrl = 'redis://localhost:6379'; // ❌ Redis without TLS

const mysqlUrl = 'mysql://user:pass@localhost/db'; // ❌ MySQL without SSL

✅ Correct

const mongoUrl = 'mongodb+srv://cluster0.example.com/app';
const redisUrl = 'rediss://cache.example.com:6380';

// http:// and ws:// are reported by their owning rules, not this one
fetch('http://api.example.com/data'); // require-https-only
const ws = new WebSocket('ws://socket.example.com'); // require-websocket-wss

Configuration

Default Configuration

{
  "browser-security/no-unencrypted-transmission": "error"
}

Options

OptionTypeDefaultDescription
allowInTestsbooleanfalseIn test files, exempt URLs whose written-down host is loopback (any scheme); a real host still reports
insecureProtocolsstring[][]Insecure protocol patterns to detect
secureAlternativesobject{}Mapping of insecure protocols to their secure alternatives
ignorePatternsstring[][]Additional safe patterns to ignore

Example Configuration

{
  "browser-security/no-unencrypted-transmission": [
    "error",
    {
      "allowInTests": true,
      "insecureProtocols": ["mongodb://", "redis://", "ftp://"],
      "secureAlternatives": {
        "mongodb://": "mongodb+srv://",
        "redis://": "rediss://"
      },
      "ignorePatterns": ["localhost", "127.0.0.1"]
    }
  ]
}

Auto-Fix Behavior

The rule offers a suggestion (not an automatic fix) on string literals that rewrites the scheme to its secure alternative — mongodb:// to mongodb+srv://, redis:// to rediss://, and any pair supplied in secureAlternatives. Template literals get no suggestion: rewriting around an interpolation is too risky.

// Before (triggers rule)
const redisUrl = 'redis://cache.example.com:6379';

// After (suggestion applied)
const redisUrl = 'rediss://cache.example.com:6379';

Best Practices

  1. Always use HTTPS: For all external API calls
  2. Use WSS for WebSockets: Encrypt WebSocket connections
  3. Database encryption: Use TLS/SSL for database connections
  4. Environment variables: Store URLs in environment variables
  5. Test exceptions: Use allowInTests: true for loopback hosts in tests; a real host in a test file still reports

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Algorithm from Variable

Why: Algorithm names from variables not traced.

// ❌ NOT DETECTED - Algorithm from variable
const algo = config.hashAlgorithm; // May be weak
crypto.createHash(algo);

Mitigation: Hardcode secure algorithms.

Third-party Crypto Libraries

Why: Non-standard crypto APIs not recognized.

// ❌ NOT DETECTED - Third-party
customCrypto.encrypt(data, key);

Mitigation: Review all crypto implementations.

Configuration-based Security

Why: Config-driven security not analyzed.

// ❌ NOT DETECTED - Config-based
const options = getSecurityOptions(); // May be weak

Mitigation: Validate security configurations.

Resources

Use this rule

npm install -D oxlint-plugin-browser-security
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-browser-security"],  "rules": {    "browser-security/no-unencrypted-transmission": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-browser-security'],    rules: {      'browser-security/no-unencrypted-transmission': 'error',    },  },});

oxlint-plugin-browser-security re-exports eslint-plugin-browser-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.