Gitleaks is a SAST (Static Application Security Testing) tool for detecting and preventing hardcoded secrets like passwords, API keys, and tokens in git repositories. Here's a comprehensive guide to configuring Gitleaks for Java projects.
Basic Gitleaks Setup
Installation
# Using Homebrew (macOS) brew install gitleaks # Using Docker docker pull zricethezav/gitleaks:latest # Using Go install go install github.com/gitleaks/gitleaks/v8@latest # Download binary from releases wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz tar -xzf gitleaks_8.18.0_linux_x64.tar.gz sudo mv gitleaks /usr/local/bin/
Basic Usage
# Scan current directory gitleaks detect --source . -v # Scan with report output gitleaks detect --source . --report-format json --report-path gitleaks-report.json # Scan specific file types gitleaks detect --source . --config-path .gitleaks.toml --no-git # Pre-commit hook gitleaks protect --staged
Comprehensive Gitleaks Configuration for Java
Example 1: Basic .gitleaks.toml for Java
# .gitleaks.toml - Basic Java configuration
title = "Gitleaks Configuration for Java Project"
[[rules]]
id = "java-properties-secrets"
description = "Detect secrets in Java properties files"
regex = '''(?i)(password|passwd|pwd|secret|key|token|auth)(\s*=\s*|\s*:\s*|\"\\s*\"\\s*:?\s*\"?)([a-zA-Z0-9+/=]{8,128})'''
tags = ["key", "Java", "properties"]
[[rules]]
id = "java-connection-strings"
description = "Detect database connection strings in Java"
regex = '''(jdbc:(mysql|postgresql|oracle|sqlserver)://[^/]+/[^?]+\\?.*?(password|user)=[^&]+)'''
tags = ["database", "Java", "JDBC"]
[[rules]]
id = "java-spring-security"
description = "Detect Spring Security secrets"
regex = '''(?i)security\\.oauth2\\.client\\.(secret|client-secret)[\\s=:\"]+([a-zA-Z0-9+/=]{8,128})'''
tags = ["Spring", "OAuth2", "security"]
[[rules]]
id = "java-api-keys"
description = "Detect API keys in Java code"
regex = '''(?i)(api[_-]?key|apikey)[\\s=:\"]+[\"']?([a-zA-Z0-9]{32,64})[\"']?'''
tags = ["api", "key", "Java"]
# Allowlist common false positives
[[allowlist]]
description = "Allow example and test credentials"
regexes = [
'''example\\.com''',
'''localhost''',
'''127\\.0\\.0\\.1''',
'''test|demo''',
'''dummy''',
'''placeholder''',
'''changeme''',
'''password''',
'''123456''',
'''admin''',
'''root'''
]
paths = [
"**/test/**",
"**/Test/**",
"**/testdata/**",
"**/examples/**",
"**/docs/**",
"**/README.md",
"**/*.test.*",
"**/*Test.*",
"**/*test.*"
]
commits = [
"commit-hash-1",
"commit-hash-2"
]
Example 2: Advanced Java-Specific Configuration
# .gitleaks.toml - Advanced Java configuration
title = "Advanced Gitleaks Configuration for Java Microservices"
version = "8.18.0"
[[rules]]
id = "java-spring-boot-application-properties"
description = "Secrets in Spring Boot application.properties/yml"
regex = '''(?i)((spring|security|management)\\.\\w+\\.(secret|key|token|password))\\s*[=:]\\s*['\"]?([a-zA-Z0-9+/=]{8,128})['\"]?'''
tags = ["Spring Boot", "application.properties", "secrets"]
[[rules]]
id = "java-environment-variables"
description = "Hardcoded environment variables in Java"
regex = '''System\\.getenv\\([\"']([^\"']+)[\"']\\)|System\\.getProperty\\([\"']([^\"']+)[\"']\\)'''
entropy = 3.5
tags = ["environment", "System.getenv"]
[[rules]]
id = "java-aws-credentials"
description = "AWS credentials in Java code"
regex = '''(aws\\.(accessKeyId|secretAccessKey)|AWS_ACCESS_KEY_ID|AWS_SECRET_ACCESS_KEY)[\\s=:\"]+['\"]?([A-Z0-9]{20})['\"]?'''
tags = ["AWS", "cloud", "credentials"]
[[rules]]
id = "java-google-cloud-keys"
description = "Google Cloud service account keys"
regex = '''\"type\": \"service_account\",\s*\"project_id\": \"[^\"]+\",\s*\"private_key_id\": \"[^\"]+\",\s*\"private_key\": \"-----BEGIN PRIVATE KEY-----'''
tags = ["GCP", "service-account", "JSON"]
[[rules]]
id = "java-jwt-secrets"
description = "JWT secrets in Java applications"
regex = '''(JWT|jwt)\\.(secret|key|signature)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=]{32,})['\"]?'''
tags = ["JWT", "authentication", "security"]
[[rules]]
id = "java-encryption-keys"
description = "Encryption keys in Java code"
regex = '''(SecretKeySpec|KeyGenerator|Cipher)\\.getInstance\\([\"']([^\"']+)[\"']\\).*?([a-zA-Z0-9+/=]{16,})'''
tags = ["encryption", "crypto", "keys"]
[[rules]]
id = "java-database-passwords"
description = "Database passwords in Java configuration"
regex = '''(datasource|database|db)\\.(password|pwd)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=@!]{4,128})['\"]?'''
tags = ["database", "password", "JDBC"]
[[rules]]
id = "java-email-credentials"
description = "Email server credentials"
regex = '''(mail|email)\\.(smtp|password|auth)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=]{4,128})['\"]?'''
tags = ["email", "SMTP", "credentials"]
[[rules]]
id = "java-payment-keys"
description = "Payment gateway API keys"
regex = '''(stripe|paypal|braintree)\\.(secret|key|token)[\\s=:\"]+['\"]?(sk_[a-zA-Z0-9]{24}|[a-zA-Z0-9]{32,64})['\"]?'''
tags = ["payment", "Stripe", "PayPal"]
# Java-specific allowlists
[[allowlist]]
description = "Allow common test and example patterns in Java"
regexes = [
'''jdbc:mysql://localhost:3306/test''',
'''jdbc:h2:mem:testdb''',
'''spring.datasource.password=password''',
'''test.*[Kk]ey''',
'''example.*[Tt]oken''',
'''mock.*[Ss]ecret''',
'''dummy.*[Pp]assword''',
'''placeholder.*[Cc]redential'''
]
paths = [
"**/src/test/**",
"**/test/**",
"**/testdata/**",
"**/test-resources/**",
"**/mock/**",
"**/stub/**",
"**/*Test.java",
"**/*test.java",
"**/*IT.java",
"**/*IntegrationTest.java",
"**/application-test.properties",
"**/application-test.yml"
]
[[allowlist]]
description = "Allow specific comments and documentation"
regexes = [
'''//.*[Ee]xample.*[Kk]ey''',
'''/\\*.*[Tt]est.*[Tt]oken.*\\*/''',
'''#.*[Dd]ummy.*[Pp]assword''',
'''<!--.*[Mm]ock.*[Ss]ecret.*-->'''
]
Integration with Java Build Tools
Example 3: Maven Integration
<!-- pom.xml - Gitleaks Maven integration -->
<project>
<build>
<plugins>
<!-- Gitleaks Maven Plugin -->
<plugin>
<groupId>com.github.zricethezav</groupId>
<artifactId>gitleaks-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<configPath>${project.basedir}/.gitleaks.toml</configPath>
<reportFormat>json</reportFormat>
<reportPath>${project.build.directory}/gitleaks-report.json</reportPath>
<verbose>true</verbose>
<redact>true</redact>
</configuration>
<executions>
<execution>
<id>gitleaks-scan</id>
<phase>verify</phase>
<goals>
<goal>protect</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Alternatively, use exec-maven-plugin -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>gitleaks-scan</id>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>gitleaks</executable>
<arguments>
<argument>detect</argument>
<argument>--source</argument>
<argument>.</argument>
<argument>--config</argument>
<argument>.gitleaks.toml</argument>
<argument>--report-format</argument>
<argument>json</argument>
<argument>--report-path</argument>
<argument>${project.build.directory}/gitleaks-report.json</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Example 4: Gradle Integration
// build.gradle - Gitleaks Gradle integration
plugins {
id 'java'
}
task gitleaksScan(type: Exec) {
commandLine 'gitleaks', 'detect', '--source', '.',
'--config', '.gitleaks.toml',
'--report-format', 'json',
'--report-path', 'build/reports/gitleaks-report.json',
'--verbose'
doFirst {
println "Running Gitleaks secret detection..."
}
doLast {
println "Gitleaks scan completed. Report available at build/reports/gitleaks-report.json"
}
}
task gitleaksProtect(type: Exec) {
commandLine 'gitleaks', 'protect', '--staged', '--verbose'
doFirst {
println "Checking staged files for secrets..."
}
}
// Add as dependency to check task
check.dependsOn gitleaksScan
// For pre-commit hooks
task installGitHooks(type: Copy) {
from new File(rootProject.rootDir, 'scripts/pre-commit')
into { new File(rootProject.rootDir, '.git/hooks') }
fileMode 0755
}
build.dependsOn installGitHooks
Git Hooks Integration
Example 5: Pre-commit Hook
#!/bin/bash # .githooks/pre-commit echo "Running Gitleaks secret detection..." # Run gitleaks on staged files GITLEAKS_RESULT=$(gitleaks protect --staged --config=.gitleaks.toml --verbose) if [ $? -eq 0 ]; then echo "✅ Gitleaks scan passed - no secrets detected in staged files" exit 0 else echo "❌ Gitleaks scan failed - potential secrets detected" echo "$GITLEAKS_RESULT" echo "" echo "Please remove the detected secrets before committing." echo "If these are false positives, update .gitleaks.toml allowlist." exit 1 fi
Example 6: Pre-push Hook
#!/bin/bash # .githooks/pre-push echo "Running comprehensive Gitleaks scan..." # Scan entire repository gitleaks detect --source=. --config=.gitleaks.toml --verbose --report-format=json --report-path=./gitleaks-report.json if [ $? -eq 0 ]; then echo "✅ Gitleaks repository scan passed" exit 0 else echo "❌ Gitleaks repository scan failed" echo "Secrets detected in repository history." echo "Check gitleaks-report.json for details." exit 1 fi
CI/CD Pipeline Integration
Example 7: GitHub Actions Workflow
# .github/workflows/gitleaks.yml
name: Gitleaks Secret Detection
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
schedule:
- cron: '0 0 * * 0' # Weekly scan
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for complete scan
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config-path: .gitleaks.toml
report-format: sarif
report-path: gitleaks-report.sarif
redact: true
verbose: true
- name: Upload Gitleaks Report
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: gitleaks-report.sarif
- name: Fail if secrets detected
run: |
if [ -f gitleaks-report.sarif ]; then
echo "❌ Secrets detected in codebase"
echo "Please check the Security tab for details"
exit 1
else
echo "✅ No secrets detected"
fi
Example 8: GitLab CI Configuration
# .gitlab-ci.yml stages: - security gitleaks_scan: stage: security image: name: zricethezav/gitleaks:latest entrypoint: [""] script: - gitleaks detect --source=. --config=.gitleaks.toml --report-format=json --report-path=gitleaks-report.json --verbose artifacts: when: always paths: - gitleaks-report.json reports: secret_detection: gitleaks-report.json allow_failure: false rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Example 9: Jenkins Pipeline
// Jenkinsfile
pipeline {
agent any
stages {
stage('Secret Detection') {
steps {
script {
sh '''
echo "Running Gitleaks secret detection..."
gitleaks detect --source=. \
--config=.gitleaks.toml \
--report-format=json \
--report-path=gitleaks-report.json \
--verbose
'''
}
}
post {
always {
archiveArtifacts artifacts: 'gitleaks-report.json', fingerprint: true
publishJSON target: [
reportDir: '.',
reportFiles: 'gitleaks-report.json',
reportName: 'Gitleaks Report'
]
}
failure {
emailext (
subject: "🚨 SECRETS DETECTED in ${env.JOB_NAME}",
body: """
Gitleaks has detected potential secrets in the codebase.
Build: ${env.BUILD_URL}
Project: ${env.JOB_NAME}
Please check the attached report and remove any detected secrets.
""",
to: "${env.CHANGE_AUTHOR_EMAIL}",
attachmentsPattern: 'gitleaks-report.json'
)
}
}
}
}
}
Custom Rules for Java-Specific Patterns
Example 10: Java-Specific Secret Patterns
# java-specific-rules.toml
[[rules]]
id = "java-spring-cloud-config"
description = "Spring Cloud Config secrets"
regex = '''spring\\.cloud\\.config\\.(token|password|username)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=]{8,128})['\"]?'''
tags = ["Spring Cloud", "config", "secrets"]
[[rules]]
id = "java-microprofile-config"
description = "MicroProfile Config secrets"
regex = '''@ConfigProperty\\(name\\s*=\\s*\"([^\"]+)\"\\s*\\)\\s*.*?=\\s*[\"']([a-zA-Z0-9+/=]{8,128})[\"']'''
tags = ["MicroProfile", "config", "secrets"]
[[rules]]
id = "java-quarkus-config"
description = "Quarkus configuration secrets"
regex = '''quarkus\\.\\w+\\.(secret|key|token|password)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=]{8,128})['\"]?'''
tags = ["Quarkus", "configuration", "secrets"]
[[rules]]
id = "java-micronaut-config"
description = "Micronaut configuration secrets"
regex = '''micronaut\\.\\w+\\.(secret|key|token|password)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=]{8,128})['\"]?'''
tags = ["Micronaut", "configuration", "secrets"]
[[rules]]
id = "java-actuator-endpoints"
description = "Spring Boot Actuator secrets"
regex = '''management\\.endpoint\\.\\w+\\.(key|secret|token)[\\s=:\"]+['\"]?([a-zA-Z0-9+/=]{8,128})['\"]?'''
tags = ["Spring Boot", "Actuator", "security"]
[[rules]]
id = "java-encrypted-properties"
description = "Jasypt encrypted properties"
regex = '''ENC\\(([a-zA-Z0-9+/=]+)\\)'''
tags = ["Jasypt", "encryption", "properties"]
[[rules]]
id = "java-keystore-passwords"
description = "Java keystore passwords"
regex = '''(keyStore|trustStore)Password[\\s=:\"]+['\"]?([a-zA-Z0-9+/=@!]{6,128})['\"]?'''
tags = ["Java", "keystore", "SSL", "TLS"]
[[rules]]
id = "java-logging-sensitivedata"
description = "Potential sensitive data in log statements"
regex = '''(LOGGER|log|logger)\\.(info|debug|warn|error)\\(.*?(password|token|secret|key).*?\\).*?'''
tags = ["logging", "sensitive data", "security"]
Monitoring and Reporting
Example 11: Custom Reporting Script
// GitleaksReportParser.java
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
public class GitleaksReportParser {
private static final ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: java GitleaksReportParser <gitleaks-report.json>");
System.exit(1);
}
String reportPath = args[0];
parseAndAnalyzeReport(reportPath);
}
public static void parseAndAnalyzeReport(String reportPath) throws Exception {
String jsonContent = new String(Files.readAllBytes(Paths.get(reportPath)));
Map<String, Object> report = mapper.readValue(jsonContent, Map.class);
@SuppressWarnings("unchecked")
List<Map<String, Object>> findings = (List<Map<String, Object>>) report.get("Findings");
System.out.println("=== GITLEAKS REPORT ANALYSIS ===");
System.out.println("Total findings: " + findings.size());
// Group by rule ID
Map<String, Long> findingsByRule = findings.stream()
.collect(Collectors.groupingBy(
finding -> (String) finding.get("RuleID"),
Collectors.counting()
));
System.out.println("\nFindings by rule:");
findingsByRule.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(entry ->
System.out.printf(" %s: %d findings%n", entry.getKey(), entry.getValue())
);
// Group by file
Map<String, Long> findingsByFile = findings.stream()
.collect(Collectors.groupingBy(
finding -> (String) finding.get("File"),
Collectors.counting()
));
System.out.println("\nTop files with findings:");
findingsByFile.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(10)
.forEach(entry ->
System.out.printf(" %s: %d findings%n", entry.getKey(), entry.getValue())
);
// Print details for critical findings
System.out.println("\nCritical findings details:");
findings.stream()
.filter(finding -> isCriticalFinding(finding))
.forEach(finding -> {
System.out.printf(" File: %s%n", finding.get("File"));
System.out.printf(" Rule: %s%n", finding.get("RuleID"));
System.out.printf(" Line: %s%n", finding.get("StartLine"));
System.out.printf(" Secret: %s%n", redactSecret((String) finding.get("Secret")));
System.out.println(" ---");
});
}
private static boolean isCriticalFinding(Map<String, Object> finding) {
String ruleId = (String) finding.get("RuleID");
return ruleId.contains("aws") ||
ruleId.contains("jwt") ||
ruleId.contains("private_key") ||
ruleId.contains("database");
}
private static String redactSecret(String secret) {
if (secret == null || secret.length() <= 8) {
return "***";
}
return secret.substring(0, 4) + "***" + secret.substring(secret.length() - 4);
}
}
Best Practices for Java Projects
- Scan Early and Often: Integrate into pre-commit hooks and CI/CD
- Customize Rules: Tailor rules for your Java framework (Spring, Quarkus, etc.)
- Regular Updates: Keep Gitleaks and rules updated
- Educate Team: Train developers on secret management
- Use Secret Management: Integrate with HashiCorp Vault, AWS Secrets Manager, etc.
- Monitor and Alert: Set up alerts for detected secrets
Conclusion
Gitleaks provides robust secret detection for Java projects when properly configured. Key recommendations:
- Comprehensive Configuration: Use Java-specific rules and allowlists
- CI/CD Integration: Automate scanning in pipelines
- Developer Workflow: Integrate with pre-commit hooks
- Regular Maintenance: Update rules and configurations
- Security Culture: Combine tools with education and processes
By implementing these configurations, Java teams can effectively prevent secret leakage and maintain strong security posture throughout the development lifecycle.