Sensitive information in source code - Credentials
Need
Removal of repository credentials from build scripts
Context
• Usage of Kotlin 1.9+ with Gradle Kotlin DSL build scripts
• Usage of private Maven repositories
Description
1. Non compliant code
repositories {
maven {
name = "companyRepo"
url = uri("https://artifacts.example.com/maven")
credentials {
username = "deploy"
password = "secretpass123"
}...The `build.gradle.kts` file below declares a private Maven repository and writes its user name and password directly in the `credentials` block. Build scripts are committed with the code, so the password is visible to everyone with access to the repository, stays in its history after it is removed and is copied into every fork, CI cache and developer machine. With it, an attacker can download private artifacts and, if the account can publish, upload a modified version of an internal library that every service then installs. The password also cannot be rotated without editing and committing the build script.
2. Steps
• Remove user names, passwords and tokens from `credentials` blocks in `build.gradle.kts` and `settings.gradle.kts`.
• Use `credentials(PasswordCredentials::class)` so Gradle reads them from `<repoName>Username` and `<repoName>Password` properties.
• Store the values in `~/.gradle/gradle.properties` on developer machines and in the CI secret store as `ORG_GRADLE_PROJECT_` environment variables.
• Use per-user or per-pipeline tokens with read-only access where publishing is not needed.
• Rotate every credential that was committed, since it remains in the repository history.
3. Secure code example
repositories {
maven {
name = "companyRepo"
url = uri("https://artifacts.example.com/maven")
credentials(PasswordCredentials::class)
}
}The corrected build script calls `credentials(PasswordCredentials::class)`. Gradle then reads the values from the `companyRepoUsername` and `companyRepoPassword` properties, derived from the repository name, which each developer sets in `~/.gradle/gradle.properties` and CI provides as the environment variables `ORG_GRADLE_PROJECT_companyRepoUsername` and `ORG_GRADLE_PROJECT_companyRepoPassword` from its secret store. The build script no longer contains any secret, and Gradle fails with a clear message when the properties are missing, instead of trying to download with empty credentials. Each developer and each pipeline can use its own token, with the minimum permissions it needs, and rotating one does not require a commit.