DevSecOps

Kotlin detekt Security Rules: Catching Vulnerabilities in Kotlin Code

detekt is Kotlin's primary static analysis tool. Its security-relevant rules catch patterns that lead to vulnerabilities in Android and server-side Kotlin.

Nayan Dey
Security Engineer
5 min read

Kotlin has become the default language for Android development and is increasingly used for server-side applications with frameworks like Ktor and Spring Boot. detekt is the de facto static analysis tool for Kotlin, similar in concept to ESLint for JavaScript or Pylint for Python.

While detekt's default ruleset focuses on code quality and style, several rules have direct security implications. And with custom rule sets, detekt can be extended to catch application-specific security patterns.

Security-Relevant Default Rules

ExplicitCollectionElementAccessMap and related rules prevent unsafe collection access patterns. In Kotlin, accessing a map with map[key] returns a nullable type, but using map.getValue(key) throws an exception if the key is missing. Mixing these patterns in security-critical code can lead to unexpected null values or crashes.

SwallowedException flags catch blocks that do not use the caught exception. In security contexts, swallowed exceptions can hide authentication failures, authorization denials, or data validation errors.

TooGenericExceptionCaught and TooGenericExceptionThrown flag overly broad exception handling. Catching Exception or Throwable can mask specific security-relevant errors by treating them the same as generic failures.

MagicNumber flags hardcoded numeric literals. In security contexts, magic numbers often represent cryptographic parameters (key lengths, iteration counts) or permission values that should be named constants for clarity and auditability.

ReturnFromFinally flags return statements in finally blocks, which can suppress exceptions including security-relevant ones.

UnsafeCallOnNullableType flags the !! operator, which throws a NullPointerException if the value is null. In server applications, this is a denial-of-service vector when processing untrusted input.

Android-Specific Security Concerns

For Android Kotlin development, detekt can catch patterns that lead to mobile security vulnerabilities:

Hardcoded credentials. Custom detekt rules can flag string literals assigned to variables with security-sensitive names. The default rules do not cover this comprehensively, but community rule sets add this detection.

Insecure random number generation. Using java.util.Random instead of java.security.SecureRandom for security-sensitive operations. A custom detekt rule can flag Random() usage in security-sensitive code paths.

WebView security. Custom rules can enforce that WebView.setJavaScriptEnabled(true) is always accompanied by appropriate input validation and that addJavascriptInterface is used cautiously.

Intent handling. Exported activities and broadcast receivers that do not validate incoming intents are a common Android vulnerability. Custom detekt rules can flag exported components that lack input validation.

Custom Security Rules

detekt's rule authoring API makes it relatively straightforward to create custom rules for your security requirements. A custom rule consists of a visitor that traverses the Kotlin AST and reports findings when it encounters problematic patterns.

Example use cases for custom security rules:

  • Enforce that all database queries use parameterized statements
  • Require that all HTTP clients use certificate pinning
  • Flag direct logging of variables that might contain sensitive data
  • Ensure cryptographic operations use approved algorithms and key lengths
  • Verify that authentication checks are present in specific code paths

Publish custom rules as a separate detekt plugin module that can be shared across projects in your organization.

Configuration

A security-focused detekt.yml:

potential-bugs:
  active: true
  UnsafeCallOnNullableType:
    active: true
  CastToNullableType:
    active: true
  
exceptions:
  active: true
  SwallowedException:
    active: true
  TooGenericExceptionCaught:
    active: true
    
style:
  active: true
  MagicNumber:
    active: true
  ReturnFromFinally:
    active: true
  ForbiddenMethodCall:
    active: true
    methods:
      - 'java.util.Random.<init>'
      - 'kotlin.io.println'

The ForbiddenMethodCall rule is particularly useful for security. You can define a list of methods that should not be used in your codebase, such as insecure random generators, deprecated cryptographic functions, or unvalidated deserialization methods.

Integration With Build Tools

For Gradle (the standard for Kotlin projects):

plugins {
    id 'io.gitlab.arturbosch.detekt' version '1.23.4'
}

detekt {
    config.setFrom("$projectDir/config/detekt/detekt.yml")
    buildUponDefaultConfig = true
    allRules = false
}

tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach {
    reports {
        sarif.required.set(true)
    }
}

SARIF output enables integration with GitHub's Security tab, making findings visible directly in pull requests.

The Kotlin-Java Boundary

Kotlin's null safety is one of its strongest security features, but it breaks down at the boundary with Java code. Platform types (types coming from Java that Kotlin cannot determine the nullability of) are treated as neither nullable nor non-nullable. This means Kotlin code calling Java methods can encounter null values without compiler warnings.

For security-critical code paths that cross the Kotlin-Java boundary, add explicit null checks even when the Kotlin compiler does not require them. detekt's UnsafeCallOnNullableType rule does not help here because platform types are not treated as nullable.

Custom detekt rules can flag platform type usage in security-sensitive code and require explicit null handling.

How Safeguard.sh Helps

Safeguard.sh extends your Kotlin security coverage beyond what detekt provides by monitoring your Gradle and Maven dependencies for known vulnerabilities. While detekt catches security anti-patterns in your Kotlin source code, Safeguard.sh generates SBOMs for your Kotlin projects, tracks CVEs in your dependency tree, and alerts you when a library you depend on is affected by a new vulnerability. For Android projects, this includes both direct dependencies and the transitive dependency tree that often contains dozens of libraries invisible to the developer.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.