Loading…
Loading…
Evaluates bytecode protection strategies (GraalVM native-image, ProGuard) for S2R platform services, detailing implementation, trade-offs, and current
This document evaluates and details the bytecode protection strategies implemented for the S2R platform's Java-based services. The primary objective is to protect proprietary algorithms and intellectual property (IP) from reverse-engineering when the platform is deployed within an API consumer's private network (VPC).
The S2R platform's architecture involves deploying Docker images containing Java Archive (JAR) files into the API consumer's environment, where the API consumer has root access to the host. This allows for trivial extraction and decompilation of JARs, posing a risk of unauthorized reverse-engineering and potential forking of the platform.
As of the latest updates, the protection status for key S2R services in the public release path is as follows:
admin-api: Ships as a GraalVM native-image binary.runtime: Ships as a GraalVM native-image binary.worker: Ships as a JVM application with ProGuard obfuscation. Apache POI library incompatibility prevents native-image conversion for this service.admin-ui: Uses esbuild for minification and bundling, which is not covered by the bytecode protection options discussed here.migrations runner: Stays as a JVM admin-api image.Development environments (build-images.ps1, dev-ci.yaml) continue to use fast ProGuard builds for rapid iteration.
The primary threat addressed by bytecode protection is an API consumer extracting and decompiling the shipped JARs to reverse-engineer proprietary algorithms and re-implement an unlicensed fork of the platform.
Proprietary surfaces identified as targets for protection include:
SoapMessageMapper.java in services/runtime.F5* and s2r_f5_learned_example derivation in services/worker.Lower-priority threats, such as license-bypass tampering, hiding platform existence, or anti-debug measures, are out of scope for this evaluation.
GraalVM native-image provides the strongest IP protection by compiling Java bytecode into a standalone native executable.
GraalVM performs Ahead-Of-Time (AOT) compilation of Java bytecode. The output is a single, statically-linked binary. This process eliminates the Java Virtual Machine (JVM) and .class files, replacing the bytecode with machine code. While class, method, and field identifiers may persist in metadata for reflection, the executable logic is entirely native code.
javax.xml.transform, javax.xml.crypto.dsig), Swagger Parser v3, OpenSAML, Apache POI.ServiceLoader-style discovery requires --initialize-at-run-time flags and resource patterns. Apache POI is a known hard blocker due to dynamic class loading and reflection-driven OOXML schema.ImmutableList NPE issues requiring --initialize-at-run-time flags.The S2R stack (JDK 25 + Spring Boot 3.5.14) is on a supported path for GraalVM native-image, with Spring Boot 3.5 and GraalVM 24/25 offering first-class support and compatibility.
ProGuard performs post-compile bytecode transformation, primarily by renaming classes, methods, and fields to short, unreadable identifiers.
ProGuard processes compiled bytecode to shrink unused code, optimize, and obfuscate. The resulting JAR still contains executable bytecode, but the identifiers are scrambled. Decompilers can still produce valid Java code, but its readability is significantly reduced due to the obfuscated names.
proguard-maven-plugin and a proguard.conf file per service. Build time increases by approximately 50% (30-60 seconds per service).retrace tool to deobfuscate stack traces for debugging.@Component, @Service), DTOs (for Jackson serialization), and various libraries (JJWT, Nimbus, Flyway, JDBC drivers). This often results in 60-80% of user-code classes remaining un-obfuscated, significantly reducing the effective protection surface.ProGuard 7.6+ supports JDK 25. The proguard-maven-plugin (8.x) integrates with Spring Boot's repackage goal, requiring careful ordering to obfuscate before fat-JAR repackaging.
This option involves shipping plain Spring Boot fat-JARs without any bytecode protection.
The platform services are built and packaged as standard Spring Boot fat-JARs, containing readily decompilable Java bytecode.
jstack, and heap dumps.docker save access can easily extract and decompile the source code.Several complementary IP protection measures exist that compose with plain bytecode:
The bytecode protection strategy for S2R services has evolved through several decisions and corrections.
The initial recommendation was to adopt Option C (plain bytecode) for v1 GA and defer Option A (GraalVM native-image) to v1.2. Option B (ProGuard) was rejected due to its illusory protection and maintenance cost.
This initial recommendation was superseded by a customer directive for extensive bytecode protection. Epic AH (#593) aimed to ship the following for v1 GA:
| Component | Intended v1 GA Protection | Notes