Back to Articles

Mining Secrets from Spring Boot Heapdumps: How pyhprof Weaponizes Actuator Endpoints

[ View on GitHub ]

Mining Secrets from Spring Boot Heapdumps: How pyhprof Weaponizes Actuator Endpoints

Hook

Every Spring Boot application with an exposed /actuator/heapdump endpoint is silently advertising a complete snapshot of its runtime secrets—passwords, API keys, tokens—all bundled in a convenient binary file for anyone who knows how to parse it.

Context

Spring Boot Actuator endpoints have become ubiquitous in cloud-native Java applications, providing observability into running services through metrics, health checks, and diagnostic dumps. Among these endpoints, /actuator/heapdump stands out as particularly powerful—and dangerous. When accessed, it generates a complete HPROF (Heap Profile) dump containing the entire state of the Java Virtual Machine's memory at that moment.

The security implications are enormous. These heap dumps contain everything: environment variables with database passwords, OAuth tokens loaded from configuration files, API keys stored in Spring's application context, and even raw HTTP request/response data still lingering in memory. The problem isn't theoretical—misconfigured Spring Boot applications regularly expose these endpoints to the internet without authentication. Tools like Eclipse Memory Analyzer Tool (MAT) and VisualVM can parse HPROF files, but they're designed for performance analysis, not security auditing. Security researchers needed something purpose-built to extract secrets from these dumps quickly, without navigating through GUI tools meant for Java developers debugging memory leaks. This is where pyhprof enters the picture: a Python library laser-focused on mining sensitive data from Spring Boot heapdumps.

Technical Insight

The HPROF binary format dates back to Java 1.0.2 and is notoriously under-documented, with significant ambiguity in how different JVM implementations serialize data. pyhprof tackles this by focusing specifically on PRIMITIVE ARRAY DUMP records, which is where Spring Framework stashes configuration properties and environment variables. The library doesn't attempt to parse the entire heap—an approach that would be both slow and unnecessary for security testing. Instead, it surgically targets the data structures most likely to contain secrets.

The library's architecture centers around two classes: HprofParser handles the binary format parsing, while ReferenceBuilder reconstructs meaningful data from the raw primitive arrays. What makes this interesting is pyhprof's handling of format ambiguity. Through empirical testing, the author identified two distinct patterns Spring uses to serialize string data in primitive arrays. The library attempts both parsing strategies and uses heuristics to determine which produced valid results:

from pyhprof.parser import HprofParser
from pyhprof.reference import ReferenceBuilder

# Parse the heap dump
with open('heapdump.hprof', 'rb') as f:
    parser = HprofParser(f)
    parser.parse()

# Build references and extract variables
builder = ReferenceBuilder(parser.records)
builder.build_references()

# Access parsed environment variables
for var_name, var_value in builder.variables.items():
    if 'password' in var_name.lower() or 'key' in var_name.lower():
        print(f"Found sensitive variable: {var_name} = {var_value}")

The Type 1 and Type 2 parsing formats differ in how they encode string length and character data within byte arrays. Type 1 assumes a specific offset pattern where length indicators precede string data, while Type 2 uses a different alignment strategy. This isn't documented anywhere in official HPROF specifications—it's reverse-engineered knowledge. When automatic detection fails (usually with dumps from non-standard JVM implementations or older Spring versions), users can force a specific type with command-line flags.

The real power comes from integration with truffleHog's regex patterns for secret detection. The spring_heapdumper.py example script doesn't just extract variables—it automatically runs dozens of regex patterns designed to catch AWS keys, private keys, Slack tokens, database connection strings, and other credential formats:

# Simplified version of the secret detection logic
import re

SECRET_PATTERNS = {
    'AWS API Key': r'AKIA[0-9A-Z]{16}',
    'RSA Private Key': r'-----BEGIN RSA PRIVATE KEY-----',
    'Generic Password': r'password["\']?\s*[:=]\s*["\']([^"\'\ ]{8,})',
}

def scan_for_secrets(variables):
    findings = []
    for var_name, var_value in variables.items():
        for secret_type, pattern in SECRET_PATTERNS.items():
            matches = re.findall(pattern, var_value, re.IGNORECASE)
            if matches:
                findings.append({
                    'type': secret_type,
                    'variable': var_name,
                    'match': matches[0][:50]  # Truncate for safety
                })
    return findings

This automated scanning transforms pyhprof from a simple parser into a security assessment tool. During a penetration test, you can download a heapdump, run pyhprof, and get an immediate inventory of exposed secrets—all without opening a Java IDE or understanding Spring's internal architecture.

The library also extracts HTTP request and response data that may still be in memory, which can reveal API endpoints, authentication headers, and session tokens. This data lives in different heap structures than configuration variables, requiring separate extraction logic that walks object references to reconstruct byte streams into readable HTTP traffic.

One clever design decision: pyhprof loads the entire heap dump into memory before processing. While this seems wasteful, it dramatically simplifies the parsing logic since HPROF files contain forward references—later records may reference objects defined earlier. Random access to the full dataset eliminates the need for multi-pass parsing or complex reference resolution algorithms.

Gotcha

The biggest limitation is RAM consumption. Since pyhprof loads the entire heap dump into memory, analyzing a 4GB heapdump requires at least 4GB of available RAM, often more during processing. There's no streaming parser, no progress indicators, and no partial result output. You start the script and wait—sometimes for several minutes on large dumps—with no feedback until it completes or crashes with a MemoryError.

Format detection failures are another pain point. While the dual-format approach handles most Spring Boot versions, edge cases exist where neither Type 1 nor Type 2 parsing produces clean results. This typically happens with heavily customized Spring configurations or when analyzing dumps from non-standard JVM implementations like GraalVM native images. When auto-detection fails, you're left manually trying -t1 and -t2 flags and visually inspecting output to determine which produced less garbage. There's no validation mechanism to definitively say "this format is correct."

The tool is also Spring-centric to the point of being nearly useless for general-purpose HPROF analysis. If you need to analyze heap dumps from non-Spring Java applications, understand object retention patterns, or investigate memory leaks, Eclipse MAT remains the better choice. pyhprof makes strong assumptions about how Spring structures data in memory—assumptions that don't hold for arbitrary Java applications.

Verdict

Use pyhprof if you're conducting security assessments of Spring Boot applications, performing red team operations where you've gained access to actuator endpoints, or auditing cloud deployments for exposed secrets in heapdumps. It excels at rapid triage: download dump, extract secrets, move on. The automated truffleHog integration makes it perfect for bulk analysis of multiple applications—scan 50 microservices' heapdumps in an afternoon. Skip it if you need general Java heap analysis, are working with non-Spring applications, or require interactive exploration of object graphs and memory structures. Also skip it for production debugging of memory leaks or performance issues—that's not what it's built for. This is a security tool masquerading as a parser, and it's excellent at that specific job while being mediocre at everything else.