Occlude¶
Opaque references to sensitive values, for Java.
Some values should not simply become text: personal and regulated data, credentials, untrusted
input from outside. Once such a value is a String in your application, nothing can tell you where
it went — a log line, an event, a prompt.
Occlude takes custody of the value and hands back an occluded reference. It travels anywhere, because holding one is not permission to read it. Turning it back into a value is the one checked operation, and it always names where the value is going.
Occluded<Mail> mail = customerMail.occlude(incoming); // the real thing stays here
vendorLlm.reveal(mail); // Denied — above that sink's ceiling
quarantinedLlm.reveal(mail); // Allowed
Two ideas, both borrowed¶
Information flow. Every value carries a label; every place a value might go declares a ceiling. Reading is decided against both. Deriving a value joins its parents' labels, so an ordinary derivation cannot weaken one — that is a theorem about the algebra rather than a rule somebody enforces. This is Denning's lattice model, applied per axis.
Object capabilities. Authority is held, never looked up. There is no registry and no
charter.get("customer-mail"). Code can occlude at a portal because something handed it that portal,
so "what can this class do?" is answered by reading its constructor parameters — and a service
handed the portal for customer disputes cannot express the operation of creating cardholder data.
What it is for¶
The case it was built for is an LLM. A model should be able to reason about a customer's email — refer to it, ask about it, act on it — without the text ever entering the conversation. It holds an identifier; the tools it may call hold the authority. Naming an occluded reference is not authority to redeem one, so a prompt injection cannot conjure a way to read a value.
The other half is the inbound direction. Anything a model produced, or anything that arrived from outside, is occluded as untrusted, and the only path from untrusted to trusted is a named derivation that declassifies — which appears in the manifest where a reviewer will see it.
Getting started¶
With Spring Boot and Postgres, one dependency:
<dependency>
<groupId>org.jwcarman.occlude</groupId>
<artifactId>occlude-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
Plain Java, the BOM, and trying it in memory are in Getting Started. Or read What Occlude Does Not Do first, if you would rather know the limits. That page is not an apology — knowing what a security library declines to promise is how you find out whether it fits.
Elsewhere¶
Requirements¶
Java 25, and Postgres 13 or later if you want durable storage. A MemoryStorage is included for tests and for
proving a policy before a database is involved.