Changelog
All notable changes to jGuard are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.4.0] - Unreleased​
Added​
- Test-specific policy overrides: New
src/test/jguard/directory support for test-only policies. Test policies extend embedded policies with additional permissions needed during testing (e.g., temp file access, thread creation). Policies are compiled by thecompileTestPoliciestask and automatically passed to the agent during test execution. - Multi-directory policy overrides: The agent now supports comma-separated paths in
-Djguard.policy.override, allowing layered policy overrides. Later directories take precedence. - Embedded external policies: Modules can now ship policies for third-party dependencies by placing them in
src/main/jguard/. These policies are compiled toMETA-INF/jguard/external/*.binin the JAR and automatically discovered by the agent alongside embedded policies. This enables applications to define capabilities for runtime dependencies (e.g., Netty, Reactor) without requiring manual-Djguard.policy.overrideconfiguration. Same signing requirements apply as embedded policies. - Audit mode summary: In audit mode, the agent now accumulates all unique denials and prints a summary at JVM shutdown. This shows all missing entitlements in one run instead of discovering them one-by-one.
- Suggested policy output: At shutdown in audit mode, the agent prints copy-paste-ready
.jguardpolicy syntax based on observed denials. This dramatically speeds up initial policy authoring for new projects. - Policy discovery debug logging: Added DEBUG-level logging for policy discovery from JARs and directories. Enable with
-Djguard.log.level=debugto diagnose policy loading issues.
Fixed​
- Gradle plugin configuration conflict: Fixed
jguardAgentconfiguration creation to usemaybeCreate()instead ofcreate(), avoiding conflicts when other plugins create the configuration first. This was blocking the per-modulemodule-info.jguardworkflow in multi-module builds. - Embedded policies not discovered during tests: Fixed policy discovery for tests by outputting compiled policies to
build/jguard-policy/META-INF/jguard/and registering this directory withsourceSets.main.output.dir(). This ensures policies are on the test classpath and properly packaged into JARs. - Gradle cross-project dependency ordering: Fixed
compileJGuardPolicytask lifecycle wiring. Policies now output to a dedicatedbuild/jguard-policy/directory (avoiding conflicts withcompileJava's output), registered viasourceSets.main.output.dir(builtBy: compileJGuardPolicy). This ensures cross-project dependencies (viaproject(':other')) automatically wait for policy compilation. - Directory-based policy discovery: Fixed agent to discover embedded policies from directories on the classpath, not just JAR files. This enables policy discovery during development/testing when using Gradle class directories.
- Gradle clean task: The
cleantask now removesbuild/jguard-policy/andbuild/test-policies/directories, preventing stale compiled policy files from causing conflicts.
[0.3.1] - 2026-01-30​
Fixed​
- Classpath module resolution: Fixed a bug where the presence of a
_global.jguardfile prevented package-prefix matching from working. Now per-module policies are correctly resolved on the classpath by matching caller packages against module names. - JDK internal native library loading: Fixed crash when JDK loads native libraries (e.g.,
extnetfor macOS sockets) with user code on the call stack. jGuard now detects when the immediate caller ofSystem.loadLibrary()is JDK code and allows it without requiring user entitlements. - Windows non-default filesystem paths: Fixed
InvalidPathExceptionon Windows when checking paths from non-default filesystem providers (e.g., ZipFS).
Changed​
- Classpath module resolution now tries package-prefix matching before falling back to the "unnamed" module policy from
_global.jguard. native.loadchecks now allow JDK internal library loads (java., jdk., sun., com.sun.) automatically.
[0.3.0] - 2026-01-25​
Added​
New Capabilities​
process.exec(pattern?)— Control process execution (Runtime.exec(),ProcessBuilder.start())- Optional pattern argument to restrict allowed commands (e.g.,
/usr/bin/java,/opt/app/bin/*) - Prevents shell escapes and command injection attacks
- Optional pattern argument to restrict allowed commands (e.g.,
fs.hardlink(root, glob)— Control hard link creation (Files.createLink())- Prevents filesystem boundary bypass attacks via hard links
- Requires root directory and glob pattern arguments
crypto.provider— Control JCE crypto provider modifications- Guards
Security.addProvider(),Security.insertProviderAt(),Security.removeProvider(),Security.setProperty() - Prevents installation of rogue cryptographic providers
- Guards
runtime.exit— Control JVM termination (System.exit(),Runtime.exit(),Runtime.halt())- Prevents rogue libraries from killing server applications
- Critical for maintaining uptime SLAs
runtime.shutdown_hook— Control shutdown hook registration (Runtime.addShutdownHook(),Runtime.removeShutdownHook())- Prevents libraries from interfering with graceful shutdown
Trusted Module Mechanism​
trusted;keyword for modules that need unrestricted access (e.g., native ML libraries)- Override-only: trusted keyword only allowed in external policy override files, not embedded policies
- Requires explicit opt-in via
-Djguard.allow.trusted=truesystem property - Security warning logged when trusted modules are loaded
- Gradle plugin
allowTrustedconfiguration property
Gradle Plugin Improvements​
- Automatic incremental builds for
compileExternalPoliciestask with proper file change detection - Test tasks automatically depend on
compileExternalPolicieswhen external policies are configured - Global policies (
_global.jguard) now apply to unnamed module (classpath code)
Agent Improvements​
- Bootstrap JAR caching with content-hash based invalidation
- Configurable cache directory via
jguard.bootstrap.cache.dirsystem property - Automatic cache invalidation when agent JAR changes (including SNAPSHOT builds)
- Configurable cache directory via
- AUDIT mode now respects explicit
jguard.log.allowed=falsesetting - Contextual keywords: all keywords (
security,module,entitle,deny,to,trusted) are now contextual, allowing package names likeio.example.security.module
Changed​
- Binary policy format version bumped to v3 (supports trusted flag)
- Bootstrap cache filename includes content hash for reliable cache invalidation
Fixed​
jguard.log.allowed=falsenow properly suppresses ALLOWED logs in AUDIT modecompileExternalPoliciestask now correctly detects file content changes- Bootstrap JAR cache no longer uses stale cached versions after rebuilds
[0.2.0] - 2026-01-13​
Added​
Multi-Module Support​
- Auto-discovery of policies embedded in signed JARs (
META-INF/jguard/policy.bin) - Per-module policy enforcement with module isolation
- Support for JPMS modular applications with multiple security domains
jguard.allowUnsignedPoliciesflag for development mode
External Policies with Grant/Deny​
- External policy files for deployment-time customization
denystatement to remove capabilities from embedded policiesdeny(defensive)to suppress warnings for intentional defensive denials_global.jguardfor environment-wide restrictions (e.g., airgapped networks)- Merge logic:
effective = (embedded ∪ external_grants ∪ global_grants) - (external_denials ∪ global_denials)
Legacy Library Support​
- External policies for third-party libraries without jGuard policies
- MODULE pattern matching for automatic modules (JAR-derived module names)
- Restrictive by default: unentitled operations are blocked
CLI Tools​
jguardc- Standalone compiler for.jguardpolicy filesjguard inspect- Inspect policies in JARs or binary filesjguard list- List all policies found in JARs on a pathjguard diff- Compare two policy filesjguard validate-override- Validate override policies
Policy Hot Reload​
- Zero-downtime policy updates via file watching
- Configurable poll interval (
jguard.reload.interval) - Support for both explicit path and discovery mode
- External policy directory watching
Compiler Enhancements​
--strictflag treats warnings as errors (useful for CI)- Redundant deny warnings when denying capabilities not in granted set
- Improved error messages with file:line:column format
Changed​
- Gradle plugin now configures tests to run on classpath (not module path) for JUnit/AssertJ compatibility
- Binary policy format version 2 includes denial support
Fixed​
- JPMS test isolation issue where test frameworks couldn't be found on module path
[0.1.0] - 2026-01-07​
Added​
- Initial release with core capability-based security model
- Policy descriptor format (
module-info.jguard) - Capabilities:
fs.read- Read files matching glob patternsfs.write- Write files matching glob patternsnetwork.outbound- Outbound network connectionsnetwork.listen- Server socket bindingthreads.create- Thread creationnative.load- Native library loadingenv.read- Environment variable accesssystem.property.read- System property readingsystem.property.write- System property writing
- ByteBuddy-based JDK instrumentation
- Gradle plugin (
io.jguard.policy) - Three enforcement modes: STRICT, PERMISSIVE, AUDIT
- Package-level entitlements with glob patterns