In the modern software development lifecycle, Java applications are built by assembling open-source dependencies, base images, and custom code. This complex supply chain introduces significant security risks, from vulnerable libraries to misconfigured containers. Aqua Security is a leading Cloud Native Application Protection Platform (CNAPP) that provides comprehensive scanning capabilities to identify and remediate these risks throughout the CI/CD pipeline and runtime environment.
This article explores how Aqua Security scans Java applications, the types of vulnerabilities it detects, and how to integrate it into your development workflow for a more secure software supply chain.
What is Aqua Security?
Aqua Security is a holistic security platform designed specifically for cloud-native applications. Its scanning capabilities cover the entire application lifecycle, from code to runtime. For Java developers, the most relevant components are:
- Aqua Trivy (Open Source): A comprehensive vulnerability scanner for containers, file systems, and Git repositories.
- Aqua CSP (Commercial Platform): Provides advanced scanning, compliance checks, and runtime security.
Why Scan Java Applications?
Java applications have unique security challenges:
- Vulnerable Dependencies: Maven and Gradle projects can pull in hundreds of transitive dependencies, any of which could contain known vulnerabilities (CVEs).
- Container Image Risks: The base image (e.g.,
openjdk:17), the JVM, and the application code itself can all introduce security issues. - Secrets in Code: Accidentally committed API keys, passwords, and certificates in source code or configuration files.
- Infrastructure as Code (IaC) Misconfigurations: Unsafe Kubernetes manifests or Dockerfiles that deploy your Java application.
Key Scanning Capabilities for Java
1. Software Composition Analysis (SCA) - Dependency Scanning
Aqua scans your project's dependency manifest files (pom.xml, build.gradle) to identify vulnerable libraries.
What it detects:
- Known vulnerabilities (CVEs) in direct and transitive dependencies
- License compliance issues
- Outdated packages with available patches
Example Vulnerabilities Found:
- Log4Shell (CVE-2021-44228) in
log4j-core - Spring4Shell (CVE-2022-22965) in Spring Framework
- Apache Commons Text RCE (CVE-2022-42889)
2. Container Image Scanning
Aqua thoroughly scans Java application container images, analyzing:
- Operating System Packages: Vulnerabilities in the base OS (e.g., Alpine, Debian)
- Java-Specific Layers:
- Base JDK/JRE image vulnerabilities
- Application JAR/WAR files
- Dependencies within the image
- Configuration Issues:
- Running as root user
- Unnecessary privileges
- Exposed sensitive ports
3. Infrastructure as Code (IaC) Security
Scans Dockerfiles, Kubernetes YAML, and Helm charts for security misconfigurations before deployment.
Java-specific IaC checks:
- Using outdated base images (
openjdk:8instead ofopenjdk:17) - Including JDK instead of JRE in production images
- Not setting memory limits for JVM in Kubernetes
- Running container as root
4. Secrets Detection
Scans code repositories and container images for accidentally exposed secrets:
- Database passwords in
application.properties - API keys in source code
- Cloud credentials in configuration files
5. Malware Detection
Identifies known malware and crypto miners in container images and dependencies.
Practical Implementation Examples
Example 1: Scanning a Java Project with Aqua Trivy
Scanning Dependencies:
# Scan a Maven project for vulnerabilities trivy fs . --scanners vuln # Scan with specific dependency focus trivy fs . --scanners vuln --include-packages "log4j*,spring-core" # Output example my-spring-app/pom.xml ════════════════════════════════════════ Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0) ┌───────────────┬───────────────┬──────────┬──────────┬───────────────────┬───────────────┬─────────────────────────────────────────────┐ │ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ ├───────────────┼───────────────┼──────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────┤ │ log4j-core │ CVE-2021-44228│ HIGH │ affected │ 2.14.1 │ 2.17.0 │ Apache Log4j2 vulnerable to remote code │ │ │ │ │ │ │ │ execution when configured to use JNDI │ └───────────────┴───────────────┴──────────┴──────────┴───────────────────┴───────────────┴─────────────────────────────────────────────┘
Scanning Container Images:
# Build your Java application image docker build -t my-java-app:latest . # Scan the image with Trivy trivy image my-java-app:latest # Scan with specific output format for CI/CD trivy image --format sarif --output results.sarif my-java-app:latest # Scan with severity threshold trivy image --severity HIGH,CRITICAL my-java-app:latest
Example 2: CI/CD Integration with GitHub Actions
.github/workflows/aqua-scan.yml
name: Aqua Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Java application
run: mvn clean package -DskipTests
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'HIGH,CRITICAL'
- name: Build Docker image
run: docker build -t my-java-app:${{ github.sha }} .
- name: Scan Docker image
uses: aquasecurity/trivy-action@master
with:
scan-type: 'image'
scan-ref: 'my-java-app:${{ github.sha }}'
format: 'table'
exit-code: 1
severity: 'CRITICAL'
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
Example 3: Aqua Enterprise Scanning in Pipeline
For commercial Aqua CSP, the scanning is typically integrated like this:
# Example Jenkins pipeline
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
sh 'docker build -t my-registry/my-java-app:${BUILD_NUMBER} .'
}
}
stage('Aqua Security Scan') {
steps {
// Scan with Aqua CSP scanner
sh 'aqua scan image my-registry/my-java-app:${BUILD_NUMBER}'
// Check for policy compliance
sh 'aqua cli scan --local image my-registry/my-java-app:${BUILD_NUMBER} --register --check-only'
}
}
stage('Deploy') {
when {
expression { currentBuild.result == 'SUCCESS' }
}
steps {
sh 'kubectl set image deployment/my-app app=my-registry/my-java-app:${BUILD_NUMBER}'
}
}
}
post {
always {
// Clean up images
sh 'docker rmi my-registry/my-java-app:${BUILD_NUMBER} || true'
}
}
}
Remediation Strategies for Common Java Findings
1. Vulnerable Dependencies
<!-- In pom.xml - BEFORE --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version> <!-- Vulnerable version --> </dependency> <!-- AFTER --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.17.1</version> <!-- Patched version --> </dependency>
Use tools like: mvn versions:use-latest-versions or ./gradlew dependencyUpdates
2. Insecure Base Images
# ❌ Insecure Dockerfile FROM openjdk:8u181 # Old, vulnerable JDK COPY target/app.jar app.jar RUN adduser -D appuser USER appuser ENTRYPOINT ["java", "-jar", "/app.jar"] # ✅ Secure Dockerfile FROM eclipse-temurin:17.0.9_9-jre-alpine # Minimal, updated JRE COPY target/app.jar app.jar RUN addgroup -S appgroup && adduser -S appuser -G appgroup USER appuser ENTRYPOINT ["java", "-jar", "/app.jar"]
3. Secrets in Configuration
// ❌ In application.properties
database.password=mysecretpassword
// ✅ Use environment variables or secret management
database.password=${DB_PASSWORD}
# Kubernetes deployment with secrets apiVersion: v1 kind: Pod metadata: name: java-app spec: containers: - name: app image: my-java-app:latest env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password
Best Practices for Java Teams
- Shift Left: Integrate scanning early in the development process, ideally in pre-commit hooks and PR checks.
- Fail Builds on Critical Issues: Configure your CI/CD pipeline to fail when critical vulnerabilities are detected.
- Use Base Image Hardening: Prefer minimal base images like
eclipse-temurin:17-jre-alpineor distroless images. - Automate Dependency Updates: Use Dependabot, Renovate, or similar tools to automatically create PRs for vulnerable dependencies.
- Define Security Policies: Establish and enforce organizational policies for vulnerability severity thresholds.
- Runtime Protection: Complement pre-production scanning with Aqua's runtime security for production environments.
Conclusion
Aqua Security provides a comprehensive scanning solution that addresses the unique security challenges of Java applications in cloud-native environments. By integrating Aqua scanning into your CI/CD pipeline, Java teams can proactively identify and remediate vulnerabilities in dependencies, container images, and configuration before they reach production. This shift-left security approach, combined with runtime protection, creates a robust defense-in-depth strategy that is essential for securing modern Java applications in today's threat landscape.
Further Reading:
- Aqua Trivy GitHub Repository
- OWASP Dependency Check (Alternative open-source tool)
- Spring Boot Security Hardening Guide