Skip to main content
Gradle Plugin Logs Exposed AWS URLs for an HourIncident
4 min readFor Security Engineers

Gradle Plugin Logs Exposed AWS URLs for an Hour

What Happened

On March 27, 2020, Danny Thomas disclosed CVE-2020-7599, a vulnerability in Gradle's plugin-publish plugin that exposed pre-signed AWS URLs in log output. Every version below 0.11.0 was affected. When developers ran the plugin with INFO or DEBUG logging enabled, their build logs captured temporary AWS credentials that remained valid for one hour. This provided enough time for an attacker monitoring those logs to upload malicious artifacts to the Gradle Plugin Portal.

The vulnerability was easy to exploit. If your CI/CD system archived build logs, anyone with read access could extract working AWS URLs. The default LIFECYCLE log level prevented exposure in typical builds, but teams running verbose logging for troubleshooting or audit purposes inadvertently exposed credentials.

Timeline

Pre-March 27, 2020: All plugin-publish versions below 0.11.0 logged pre-signed AWS URLs when INFO or DEBUG logging was active. The one-hour validity window meant credentials remained exploitable long after the build completed.

March 27, 2020: Danny Thomas disclosed the vulnerability. Gradle released version 0.11.0 with the logging behavior corrected.

Post-disclosure: Organizations running affected versions with verbose logging had potentially exposed credentials in archived build logs, CI/CD system outputs, and log aggregation platforms.

Which Controls Failed or Were Missing

Secrets in logs: The plugin wrote sensitive authentication material to stdout without considering log level implications. Logs are semi-public artifacts — they get archived, forwarded to SIEM systems, backed up to object storage, and viewed by developers who shouldn't need production credentials.

Least privilege logging: Teams enabled INFO or DEBUG logging globally rather than scoping verbose output to specific tasks. When you run ./gradlew --info publishPlugins, every task in your build gets verbose logging, not just the ones you're debugging.

Log retention without scrubbing: CI/CD platforms archived complete build output indefinitely. No process existed to detect or redact credentials from historical logs after the vulnerability disclosure.

Credential time-boxing: While the one-hour validity window limited exposure compared to permanent credentials, it still provided a meaningful attack window. An attacker monitoring logs in near-real-time could act before expiration.

What Standards Require

OWASP ASVS v4.0.3 Requirement 8.3.4 specifies that sensitive data must not be logged. This includes "authentication material" — exactly what pre-signed URLs represent. Your logging framework should classify credential types and block them at the source.

PCI DSS v4.0.1 Requirement 3.3.1 prohibits displaying full authentication data. While this requirement focuses on payment card data, the principle extends to any credential: if it grants access, it shouldn't appear in logs. Even temporary credentials violate this control if they're valid long enough for exploitation.

NIST 800-53 Rev 5 AU-9 (Protection of Audit Information) requires protecting audit records from unauthorized access and modification. Your CI/CD logs are audit records. When you store them in S3 buckets with overly permissive IAM policies or expose them through unauthenticated build status pages, you're failing this control.

ISO/IEC 27001:2022 Annex A.8.11 (Data Masking) requires masking sensitive information in logs. You need both preventive controls (don't log credentials) and detective controls (scan existing logs for leaked secrets).

Lessons and Action Items for Your Team

Configure log levels per task, not globally. Instead of ./gradlew --info, use ./gradlew publishPlugins --info or configure task-specific logging in your build.gradle:

tasks.named('publishPlugins') {
    logging.level = LogLevel.INFO
}

This limits verbose output to the specific task you're troubleshooting.

Implement structured logging with field-level controls. Replace string concatenation with structured formats (JSON, logfmt) where you can mark fields as sensitive:

logger.info {
    "plugin_published" to mapOf(
        "plugin_id" to pluginId,
        "version" to version,
        "upload_url" to Secret(url) // Automatically redacted
    )
}

Scan your log archives for exposed credentials now. Run tools like truffleHog or gitleaks against your CI/CD log storage:

trufflehog filesystem --directory=/var/log/jenkins \
  --only-verified --json > findings.json

Don't assume the vulnerability window has closed. Those archived logs still contain valid patterns that could be reactivated if AWS credentials are rotated improperly.

Set maximum credential validity periods. Pre-signed URLs don't need hour-long windows for most operations. Configure your upload process to generate 5-minute credentials:

val expiration = Date(System.currentTimeMillis() + 300000) // 5 minutes

This reduces the exploitation window by 92% without impacting legitimate use.

Treat CI/CD logs as sensitive data in your data classification scheme. Apply the same retention, access control, and encryption requirements you use for application logs that might contain PII. If your Jenkins instance allows anonymous read access to build logs, you're one plugin vulnerability away from credential exposure.

Automate dependency updates for build tooling. Your application dependencies probably have automated scanning and update processes. Your build plugins need the same treatment. Add Gradle plugin versions to Dependabot or Renovate:

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "gradle"
    directory: "/"
    schedule:
      interval: "weekly"

The Gradle plugin-publish vulnerability was fixed within hours of disclosure, but only for teams who updated promptly.

Review your SIEM ingestion rules. If you forward CI/CD logs to Splunk or Datadog, configure field extraction rules to detect and mask credential patterns before indexing. Redacting at ingestion time prevents the data from ever reaching your log storage.

This incident demonstrates that security vulnerabilities don't always involve buffer overflows or SQL injection. Sometimes they're just a developer writing logger.info(url) without considering where that log line will end up. Your controls need to account for that.

CVE-2020-7599

Topics:Incident

You Might Also Like