Skip to main content
None of these nine patterns is a defect on its own. Each one is a way a vulnerability gets introduced later. eval with a literal string is safe until the string becomes dynamic. A query built by concatenation is safe until one of its values comes from a request. Because the risk is real but latent, security smells count as Blockers, alongside hardcoded secrets, rather than as structural warnings like file length. All nine are detected across TypeScript, JavaScript, Go, Python, Ruby, C#, Java, and Rust wherever they apply, and enableSecuritySmells enables or disables the group. Not every pattern exists in every language: Java has no dynamic code evaluation in the sense the eval rule means, so its process-execution check is a separate rule, and Rust has neither.

Patterns

eval() / exec() - evalUsage

Calls to eval() in JavaScript and TypeScript, and exec() in Python and Go. These execute whatever string they are given as code, so if any part of that string ever becomes user-controlled, it is a direct code-injection route.
A literal argument today is still a risk, because the next change to that code may make it dynamic without anyone reconsidering the call. A dispatch table or a purpose-built expression parser removes the category entirely.

SQL concatenation - sqlConcatenation

SQL assembled by string concatenation or interpolation, which is the root cause of almost every SQL injection vulnerability.
Only uppercase SQL keywords are matched (SELECT, INSERT, UPDATE, DELETE, DROP), so an error message containing the word “delete” is not flagged. Parameterised queries, or a query builder that handles escaping, remove the risk entirely.

Insecure RNG - insecureRandom

A non-cryptographic random number generator used where cryptographic randomness is expected: session tokens, CSRF nonces, password reset links. These generators are predictable enough to be guessed by an attacker who tries. Use crypto.randomBytes in Node, crypto/rand in Go, or secrets in Python for anything security-sensitive.

ReDoS-risk regex - unsafeRegex

Regular expressions with nested quantifiers ((a+)+, (a|aa)+), which can backtrack catastrophically on certain inputs. A short crafted string can occupy a CPU core for minutes, so any regex applied to untrusted input becomes a denial-of-service route. Detected in all four languages. Iris Code flags the pattern itself; the fix is to rewrite it without the nesting, or to use a regex engine that does not backtrack.

Hardcoded localhost URL - hardcodedLocalhost

http://localhost or http://127.0.0.1 committed into production code. In production the call either fails, or reaches whatever else happens to be listening on that port on the server.
Test files are skipped. A localhost URL in *.test.ts or *_test.go is usually intentional.

TLS verification disabled - disabledTlsVerification

Configuration that tells an HTTPS client to accept any certificate, including expired and self-signed ones. It is usually added to work around a certificate problem in development and then ships by accident. Against a man-in-the-middle attacker, the connection offers no more protection than plain HTTP.

Debug flag enabled - debugFlagsEnabled

debug: true in a configuration object committed to production code. Debug modes typically increase log verbosity, relax security controls, and expose internal state through error messages users can see.
Test files are skipped. debug: true in a test setup file is intentional.

Weak hashing - weakHashing

Use of MD5 or SHA-1 in hashing calls. Both are cryptographically broken, with collisions cheap enough to generate that neither belongs in password storage, signatures, or integrity verification. Use SHA-256 or stronger for integrity checks, and bcrypt or argon2 for password storage. A plain hash of any algorithm is unsuitable for passwords.

Open redirect - openRedirect

A redirect that forwards to a URL taken from user input without validation. An attacker can then distribute a link on your own domain, which your users have reason to trust, that sends them to a phishing site. Flagged when a redirect call (res.redirect(...) in Express, http.Redirect(...) in Go) receives a value directly from a request parameter. Validate the destination against a list of paths you control.

CLI scanning

iris security is free and needs no account:
Worth adding to CI even without a Pro licence. It checks all nine patterns on every push and runs independently of a full iris check.

Configuration

On by default. To switch the group off:
To suppress squiggles and Problems panel entries while keeping the sidebar findings and scoring:

Scoring

Each security smell type has its own configurable weight under healthScoreWeights (Pro). Defaults:
These are the global defaults. The security preset raises several of them - evalUsage and sqlConcatenation to 8, disabledTlsVerification and openRedirect to 12, weakHashing to 8, debugFlagsEnabled to 4, insecureRandom to 3, and hardcodedLocalhost to 2 - see Scoring Weights for the full picture.
Security smells count as Blockers rather than Warnings. When evaluating gate readiness, a file containing one is treated the same as a file containing a leaked credential.

Failing a build on them (Pro)

gateMaxSecuritySmells caps the total across the workspace, enforced by the CLI, the pre-push hook and the build hook, the same way gateMaxSecrets caps secrets.
Set it to 0 to require a clean workspace. Leave it unset while working through an existing backlog, since a gate that fails on every run tends to get disabled. See Gate limits.

Inline diagnostics

With enableInlineDiagnostics enabled and inlineDiagnostics.securitySmells left at true, every finding gets a warning-severity squiggle and a Problems panel entry naming the pattern and the risk.
If your team treats these as hard blockers, promote all nine to errors at once with "severityOverrides": { "security-smell": "error" }. The override applies to the whole category; there is currently no way to raise one pattern independently of the other eight.