When should you NOT use string templates, and what risks (injection, locale, logging) do they introduce?
answer
- templates do NO escaping
- SQL/HTML/shell + user input = injection
- use parameterized queries, arg lists, escaping libs
- toString() numbers aren't locale-aware
- logging: eager eval + PII leakage
basics
~20 sTemplates just paste text, so don't use them to build SQL, HTML, or shell commands from user input — that's an injection risk. Also be careful logging sensitive data and that number formatting may not match a user's locale.
solid answer
~40 sString templates perform raw textual substitution via `toString()` — they do **no** escaping, encoding, or parameterization. So building queries or markup by interpolation is dangerous: `"SELECT * FROM users WHERE name = '$name'"` is a SQL-injection vector; use parameterized statements / prepared statements instead. Likewise interpolating into HTML invites XSS — use a templating engine that escapes. For shell commands, interpolation enables command injection; pass argument lists, not interpolated strings. Beyond security: interpolated numbers use `toString()`, which is locale-independent for primitives and won't honor a user's decimal/grouping conventions — use `NumberFormat`/`String.format` for user-facing values. And in logging, interpolating objects can leak secrets/PII because `toString()` may expose fields; templates also eagerly build the string even when the log level is disabled, unlike lazy logging APIs.
code
kotlin · 8 lines// BAD: injection
val sql = "SELECT * FROM u WHERE name = '$name'"
// GOOD: parameterized
val stmt = conn.prepareStatement("SELECT * FROM u WHERE name = ?")
stmt.setString(1, name)
// Lazy logging avoids eager template building when DEBUG is off
log.debug { "loaded ${expensiveDescribe()}" }go deeper
Knows templates just paste text and shouldn't be used for SQL from user input.
Names injection categories (SQL/XSS/command) and the parameterization/escaping fixes.
Adds locale-aware formatting and logging concerns (eager evaluation, PII) and chooses the right tool per context.
Codifies guidelines (no interpolation across trust boundaries, redacted toString(), lazy logging) and reviews for these in the codebase.
## Templates are dumb substitution A string template only evaluates expressions and concatenates their `toString()` output. It performs **no escaping, sanitization, encoding, or parameter binding**. That property drives every risk below. ## SQL injection ```kotlin // DANGEROUS - never do this val sql = "SELECT * FROM users WHERE name = '$name'" ``` If `name` is `'; DROP TABLE users; --`, the query is corrupted. **Fix:** use parameterized queries / `PreparedStatement` (or a JDBC/JPA/Exposed binding) so the value is bound, never spliced as text. ## XSS / HTML injection Interpolating untrusted input into HTML produces unescaped markup, enabling cross-site scripting. Use a template engine (Thymeleaf, kotlinx.html) that HTML-escapes, or escape explicitly. ## Command injection ```kotlin // DANGEROUS Runtime.getRuntime().exec("cp $userPath /tmp") ``` Interpolating into a shell string lets an attacker inject commands. Pass an **argument array** (`ProcessBuilder(listOf("cp", userPath, "/tmp"))`) so the OS treats `userPath` as a single argument. ## Locale & number formatting Templates call `toString()`, which for `Double`/`Int` is locale-independent (always a `.` decimal separator, no grouping). For user-facing money, percentages, or large numbers, that's wrong in many locales. Use `NumberFormat.getInstance(locale)` or `String.format(locale, ...)`: ```kotlin val price = 1234.5 println("$price") // 1234.5 (not localized) println("%,.2f".format(price)) // 1,234.50 (default locale grouping) ``` ## Logging concerns 1. **PII / secrets leakage:** interpolating a domain object calls its `toString()`, which may include passwords, tokens, or personal data. Keep `toString()` clean or redact. 2. **Eager evaluation:** `log.debug("x=$expensive()")` builds the whole string even when DEBUG is off, because the template is evaluated before the call. Prefer lazy logging (`log.debug { "x=${expensive()}" }` style lambdas, or guard with `isDebugEnabled`). ## When templates ARE the right tool For trusted, internal, non-structured text — log messages with safe data, exception messages, building display strings from your own values — templates are clear and idiomatic. The rule of thumb: never use raw interpolation to construct a string that is *parsed by another system* (SQL engine, HTML parser, shell) from untrusted input. ## Summary - No escaping → never interpolate untrusted input into SQL/HTML/shell. - Use parameterization / escaping / argument lists instead. - Use locale-aware formatting for user-facing numbers. - Watch eager evaluation and PII in logs.
- Why is interpolating into a log statement potentially wasteful?The template is evaluated before the log call, so the string (and any expensive toString()) is built even when that log level is disabled. Use a lazy lambda overload or an isXEnabled guard.
- How should you safely include user input in SQL?Never interpolate it; use parameterized/prepared statements (or an ORM/DSL binding) so the value is bound, not concatenated into the SQL text.
A template is a copy-paste, not a security guard: it pastes exactly what you give it, so if the input is malicious the output is too.
saying these in an interview costs you the question
- Builds SQL or shell commands with $-interpolated user input
- Assumes templates escape HTML or SQL automatically
- Thinks interpolated numbers are locale-formatted
- Unaware that log templates evaluate eagerly
- Logs whole domain objects without considering PII in toString()