Experimental: This feature is under active development. APIs and behavior may change.
A Java agent for runtime capability monitoring and policy enforcement. Instruments JDK classes to detect and optionally block capability usage at runtime.
java -javaagent:jcapslock-agent.jar -jar myapp.jarOutput shows which capabilities are used and the call stack:
[CAPSLOCK] CAPABILITY_FILES:
com.example.MyApp.readConfig()
com.example.Main.main()
java -javaagent:jcapslock-agent.jar=policy.yaml -jar myapp.jarWhen a blocked capability is used, throws SecurityException:
SecurityException: [CAPSLOCK] CAPABILITY_FILES blocked for com.example.untrusted.MaliciousLib
policies:
- package: com.example.untrusted
blocked:
- CAPABILITY_FILES
- CAPABILITY_NETWORK
- CAPABILITY_EXEC
- package: com.other.lib
blocked:
- CAPABILITY_EXECPackages are matched by prefix - blocking com.example also blocks com.example.sub.
-
Instrumentation: Uses ASM to instrument JDK methods that represent capabilities (e.g.,
FileInputStream,Socket,Runtime.exec) -
Stack inspection: When an instrumented method is called, walks the call stack to find application code (skipping JDK frames)
-
Policy check: If a policy file is provided, checks if any caller package is blocked for the capability
-
Logging: Always logs capability usage with full stack trace to stderr
mvn clean package -pl agent -amThe shaded JAR is at agent/target/jcapslock-agent-1.0-SNAPSHOT.jar.
Use DEFAULT in the blocked list to block all capabilities NOT in the snapshot for a package:
policies:
- package: com.example.myapp
blocked:
- DEFAULT # blocks all capabilities not in snapshot.jsonThe agent loads .capslock/snapshot.json (relative to policy file) and allows only
capabilities that exist in the snapshot for that package. Any capability usage not
in the snapshot is blocked.
Proof of Concept: The enforcement mode is experimental and can be evaded. It should be used as one layer in a defense-in-depth strategy, not as a complete security solution.
Known evasion vectors:
- Async/threaded code: Stack inspection won't show original caller after handoff to thread pool
- Reflection: Dynamically invoked methods bypass static analysis
- Native code: JNI and
sun.misc.Unsafecan perform any operation - External processes: Code executed via
Runtime.execis not monitored - Class loading tricks: Custom classloaders can load uninstrumented code
The static analysis also has inherent limitations:
- Reflection targets cannot be determined statically and lead to overapproximations
Capabilities are loaded from java-interesting.cm in the core module.
See the core module for the full list of tracked JDK methods.