Skip to content

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.