This document explains the DIFC labeling system used in this package. All implementations and tests MUST follow these rules.
DIFC uses two types of labels to control information flow:
- Secrecy Labels: Control who can read confidential information
- Integrity Labels: Control who can modify trusted resources
Both agents and resources have secrecy and integrity labels. Labels are sets of tags (strings).
Terminology note: The label type is called "SecrecyLabel" (or "secrecy label"). The tag values inside a secrecy label follow the pattern
private:<scope>(e.g.private:octo-org,private:octo-org/my-repo,private:user). An empty secrecy label[]means public data. There is no special tag named"secret"in the current implementation — all sensitive data is scoped withprivate:prefixed tags so that clearance can be granted at the appropriate owner/repo granularity.
A.secrecy= Agent's secrecy label (set of tags)A.integrity= Agent's integrity label (set of tags)R.secrecy= Resource's secrecy label (set of tags)R.integrity= Resource's integrity label (set of tags)⊇means "is a superset of" (contains all elements of)
For an agent to READ a resource:
-
Secrecy Check:
A.secrecy ⊇ R.secrecy- Agent must have clearance for all secrecy tags on the resource
- Example: To read a
{secret, confidential}document, agent must have at least{secret, confidential}in its secrecy label
-
Integrity Check:
R.integrity ⊇ A.integrity- Resource must be at least as trustworthy as the agent requires
- Example: If agent requires
{verified}integrity, resource must have at least{verified}
For an agent to WRITE to a resource:
-
Secrecy Check:
R.secrecy ⊇ A.secrecy- Resource must accept all agent's secrecy tags (no information leak)
- Example: Agent with
{secret}cannot write to a{}(public) resource
-
Integrity Check:
A.integrity ⊇ R.integrity- Agent must be at least as trustworthy as resource requires
- Example: To write to a
{production}resource, agent must have at least{production}integrity
For read-write operations, BOTH read AND write rules must be satisfied.
Agent: secrecy={private:octo-org/my-repo}, integrity={}
Resource: secrecy={}, integrity={}
Write Check:
Secrecy: R.secrecy ⊇ A.secrecy → {} ⊇ {private:octo-org/my-repo} → FALSE
Result: DENIED (would leak private-repo data to public)
Agent: secrecy={}, integrity={trusted, verified}
Resource: secrecy={}, integrity={}
Read Check:
Integrity: R.integrity ⊇ A.integrity → {} ⊇ {trusted, verified} → FALSE
Result: DENIED (resource is not trustworthy enough for agent)
Agent: secrecy={private:octo-org/my-repo, private:octo-org}, integrity={}
Resource: secrecy={private:octo-org/my-repo}, integrity={}
Read Check:
Secrecy: A.secrecy ⊇ R.secrecy → {private:octo-org/my-repo, private:octo-org} ⊇ {private:octo-org/my-repo} → TRUE
Integrity: R.integrity ⊇ A.integrity → {} ⊇ {} → TRUE
Result: ALLOWED
Agent: secrecy={}, integrity={production, verified}
Resource: secrecy={}, integrity={production}
Write Check:
Secrecy: R.secrecy ⊇ A.secrecy → {} ⊇ {} → TRUE
Integrity: A.integrity ⊇ R.integrity → {production, verified} ⊇ {production} → TRUE
Result: ALLOWED
The public internet has empty labels: secrecy={}, integrity={}.
-
An agent with
secrecy={private:octo-org/my-repo}CANNOT write to the public internet- Because:
{} ⊇ {private:octo-org/my-repo}is FALSE (would leak private-repo data)
- Because:
-
An agent with
integrity={trusted}CANNOT read from the public internet- Because:
{} ⊇ {trusted}is FALSE (source not trusted enough)
- Because:
The DIFC evaluator supports three mutually exclusive enforcement modes. You can only enable ONE mode at a time.
Use the --guards-mode flag to specify the enforcement mode:
# Guards are auto-enabled when a policy is detected
./awmg --guards-mode strict
# Use filter mode
./awmg --guards-mode filter
# Use propagate mode
./awmg --guards-mode propagate| Flag | Description | Default |
|---|---|---|
--guards-mode |
Enforcement mode: strict, filter, or propagate |
strict |
Note: Guards are automatically enabled when an allow-only policy is detected in the configuration. No explicit enable flag is needed.
| Environment Variable | Description | Equivalent Flag |
|---|---|---|
MCP_GATEWAY_GUARDS_MODE |
Enforcement mode: strict, filter, propagate |
--guards-mode |
Example:
export MCP_GATEWAY_GUARDS_MODE=filter
./awmg --config-stdin < config.json[gateway]
guards_mode = "propagate" # strict, filter, or propagateThe JSON config schema supports guard and policy fields:
{
"mcpServers": {
"github": {
"type": "stdio",
"container": "ghcr.io/github/github-mcp-server:latest",
"guard": "github-guard",
"guard-policies": {
"allow-only": {
"repos": ["owner/repo"],
"min-integrity": "none"
}
}
},
"filesystem": {
"type": "stdio",
"container": "mcp/filesystem:latest",
"guard": "fs-guard"
}
},
"guards": {
"github-guard": {
"type": "wasm",
"path": "/guards/github.wasm",
"config": {}
},
"fs-guard": {
"type": "noop"
}
},
"gateway": {
"port": 3000,
"domain": "localhost",
"apiKey": "your-api-key"
}
}Extension Fields:
mcpServers.<server>.guard- Name of the guard to use for this servermcpServers.<server>.guard-policies- Per-server allow-only policiesguards- Map of guard name to guard configurationguards.<name>.type- Guard type (wasm,noop, etc.)guards.<name>.path- Path to guard implementation (forwasmtype)guards.<name>.config- Guard-specific configuration object
Important: Filter and propagate modes are mutually exclusive. Attempting to use both will result in an error:
Error: invalid --guards-mode flag: invalid guards mode "both": must be one of: strict, filter, propagate
The DIFC evaluator supports three enforcement modes:
In strict mode, any access that would violate DIFC rules is blocked. This provides the strongest security guarantees.
In filter mode:
- Reads: Allowed, but inaccessible items are filtered out of collections
- Writes: Blocked if they violate DIFC rules (same as strict mode)
In propagate mode:
- Reads: Always allowed, but the agent's labels are automatically adjusted:
- If the agent reads a resource with secrecy tags not in the agent's secrecy label, those missing tags are added to the agent's secrecy label (agent becomes "tainted" with secret data)
- If the agent reads a resource missing integrity tags that the agent has, those missing tags are removed from the agent's integrity label (agent is "influenced" by untrusted data)
- Writes: Blocked if they violate DIFC rules (same as strict mode)
Key point: Propagate mode has NO effect on writes. Write violations are always blocked.
Example 1: Reading Secret Data (Secrecy Propagation)
Before:
Agent: secrecy={}, integrity={}
Resource: secrecy={secret}, integrity={}
Read Check (propagate mode):
Secrecy: A.secrecy ⊇ R.secrecy → {} ⊇ {secret} → FALSE
Action: Add {secret} to agent's secrecy label
Result: ALLOWED (with propagation)
After:
Agent: secrecy={secret}, integrity={}
Implication: Agent can no longer write to public resources (secrecy leak protection)
Example 2: Reading Untrusted Data (Integrity Propagation)
Before:
Agent: secrecy={}, integrity={trusted, verified}
Resource: secrecy={}, integrity={}
Read Check (propagate mode):
Integrity: R.integrity ⊇ A.integrity → {} ⊇ {trusted, verified} → FALSE
Action: Remove {trusted, verified} from agent's integrity label
Result: ALLOWED (with propagation)
After:
Agent: secrecy={}, integrity={}
Implication: Agent can no longer write to high-integrity resources
Example 3: Write Still Blocked in Propagate Mode
Agent: secrecy={secret}, integrity={}
Resource: secrecy={}, integrity={}
Write Check (propagate mode):
Secrecy: R.secrecy ⊇ A.secrecy → {} ⊇ {secret} → FALSE
Result: DENIED (propagate mode does not affect writes)
The CheckFlow(target) method checks if source ⊆ target (source has no tags that target doesn't have):
// SecrecyLabel.CheckFlow(target) returns true if all tags in source are also in target
// i.e., source ⊆ target (source is a subset of target)
func (source *SecrecyLabel) CheckFlow(target *SecrecyLabel) (bool, []Tag)
// IntegrityLabel.CheckFlow(target) returns true if all tags in source are also in target
// i.e., source ⊆ target (source is a subset of target)
func (source *IntegrityLabel) CheckFlow(target *IntegrityLabel) (bool, []Tag)CRITICAL: To check A ⊇ B (A contains all of B), call B.CheckFlow(A).
The evaluator uses these CheckFlow calls to implement the DIFC rules:
// For READ access:
// Secrecy: A.secrecy ⊇ R.secrecy → resource.Secrecy.CheckFlow(agentSecrecy)
// Integrity: R.integrity ⊇ A.integrity → resource.Integrity.CheckFlow(agentIntegrity)
// For WRITE access:
// Secrecy: R.secrecy ⊇ A.secrecy → agentSecrecy.CheckFlow(&resource.Secrecy)
// Integrity: A.integrity ⊇ R.integrity → agentIntegrity.CheckFlow(&resource.Integrity)Remember: X.CheckFlow(Y) returns true when X ⊆ Y (all tags in X are in Y).
So to check A ⊇ B, call B.CheckFlow(A).
// Create evaluator with propagate mode
evaluator := difc.NewEvaluatorWithMode(difc.EnforcementPropagate)
// Evaluate read access
result := evaluator.Evaluate(agentSecrecy, agentIntegrity, resource, difc.OperationRead)
if result.IsAllowed() {
// Apply label propagation if needed
if result.RequiresPropagation() {
agentLabels.ApplyPropagation(result)
// Agent's labels have been updated
}
// Proceed with read
}When writing tests:
- Empty labels
{}represent public/untrusted resources - To test secrecy violations, give the agent secrecy tags the resource lacks
- To test integrity violations, give the agent integrity tags the resource lacks
- For reads: agent needs clearance (secrecy), resource needs trust (integrity)
- For writes: resource needs to accept secrets (secrecy), agent needs trust (integrity)
- For propagate mode: verify that labels are correctly added/removed after reads