jGuard v0.4.0 Released
We're excited to announce the release of jGuard v0.4.0, focused on developer experience, third-party library support, and denial observability. This release makes it dramatically easier to write your first policy and to detect when third-party libraries silently swallow security denials.
What's New in v0.4.0โ
Audit Mode: Write Your First Policy in One Runโ
The biggest developer experience improvement in v0.4.0 is the overhauled audit mode. Instead of discovering missing entitlements one at a time, audit mode now:
- Accumulates all unique denials during the entire application run
- Prints a summary at JVM shutdown showing all denied operations
- Generates copy-paste-ready
.jguardpolicy based on observed denials
./gradlew runWithAgent -Pjguard.mode=audit
At shutdown you'll see:
// ============================================================
// jGuard Audit Mode - Suggested Policy
// Based on 5 denied operation(s)
// ============================================================
// Suggested policy for module 'com.example.app':
security module com.example.app {
entitle com.example.app.. to fs.read("/", "**");
entitle com.example.app.. to network.outbound;
entitle com.example.app.. to system.property.read("*");
entitle com.example.app.. to threads.create;
}
Copy the output, tighten the wildcards to specific paths and hosts, and switch to strict mode. What used to take dozens of trial-and-error runs is now a single pass.
Embedded External Policiesโ
Modules can now ship policies for their runtime dependencies directly in the JAR. Place .jguard files in src/main/jguard/ named after the target module:
src/main/jguard/
โโโ io.netty.common.jguard
โโโ com.google.api.client.jguard
โโโ reactor.core.jguard
The Gradle plugin compiles these to META-INF/jguard/external/*.bin and the agent discovers them automatically โ no -Djguard.policy.override needed.
// src/main/jguard/io.netty.common.jguard
security module io.netty.common {
entitle io.netty.common.. to threads.create;
entitle io.netty.common.. to native.load;
entitle io.netty.common.. to system.property.read("*");
}
This is ideal for applications that know what their dependencies need at build time. Same signing requirements apply as embedded policies.
Test-Specific Policiesโ
New src/test/jguard/ directory support for test-only policy extensions:
// src/test/jguard/com.example.app.jguard
security module com.example.app {
entitle com.example.app.. to fs.write("/tmp", "**");
entitle com.example.app.. to threads.create;
}
Test policies are compiled by compileTestPolicies and automatically passed to the agent during test execution. Your production policy stays minimal while tests get the extra permissions they need.
Denial Observabilityโ
When jGuard denies an operation in STRICT mode, it throws SecurityException. But third-party libraries often catch Exception broadly, silently swallowing the denial. v0.4.0 makes swallowed denials impossible to miss:
Mode-Aware Log Levelsโ
- STRICT mode: Denials now log at ERROR level (previously WARN)
- AUDIT/PERMISSIVE: Denials remain at WARN
Since the log line fires before the exception is thrown, ERROR-level denials are visible in logs even when a library's catch (Exception e) block swallows the SecurityException.
JMX Denial Countersโ
A new io.jguard:type=DenialCounters JMX MBean is always active with zero configuration:
- Total denial count across all operations
- Per-operation counts for all 14 capabilities (fs.read, network.outbound, threads.create, etc.)
Connect with JConsole, VisualVM, or any JMX client to monitor denials in real time. Wire the counters into your existing monitoring (Prometheus JMX exporter, Datadog, etc.) for production alerting.
Full Stack Tracesโ
Enforcement error handling now includes full exception stack traces in log output, making it easier to diagnose where and why errors occur.
Multi-Directory Policy Overridesโ
The agent now supports comma-separated paths in -Djguard.policy.override:
java -Djguard.policy.override=/etc/myapp/policies,/etc/myapp/env-overrides \
-javaagent:jguard-agent.jar -jar app.jar
Later directories take precedence, enabling layered policy configurations for different deployment environments.
Policy Discovery Debug Loggingโ
Enable -Djguard.log.level=debug to see exactly which JARs contain policies, what external entries are found, and how the final module list is assembled. Invaluable for diagnosing "policy not found" issues.
Getting Startedโ
Add jGuard to your Gradle project:
plugins {
id "io.jguard.policy" version "0.4.0"
}
dependencies {
implementation("io.jguard:jguard-core:0.4.0")
}
Create your policy in module-info.jguard:
security module com.example.myapp {
entitle com.example.myapp.http.. to network.outbound;
entitle com.example.myapp.io.. to fs.read(data, "**");
entitle com.example.myapp.main to runtime.exit;
}
Run with enforcement:
./gradlew runWithAgent
Or discover what you need first:
./gradlew runWithAgent -Pjguard.mode=audit
Resourcesโ
What's Nextโ
We're already working on v0.5.0, which will focus on:
- New capabilities:
jmx.monitor,runtime.stack_trace,fs.symlink - Prometheus/Micrometer metrics integration
- IDE plugin for IntelliJ IDEA
- Structured logging (JSON format)
Thank you to all our contributors!
