@mondaydotcomorg/atp-provenance
Version:
CAMEL-inspired provenance security for LLM applications - track data origin and enforce security policies
479 lines (368 loc) • 12 kB
Markdown
# @mondaydotcomorg/atp-provenance
CAMEL-inspired provenance security for LLM applications - track data origin and enforce security policies to defend against prompt injection attacks.
## Overview
This package implements provenance tracking and security policy enforcement inspired by Google Research's CAMEL paper. It provides three modes with different security/performance trade-offs to protect against prompt injection, data exfiltration, and other LLM security threats.
## Installation
```bash
npm install @mondaydotcomorg/atp-provenance
```
## Architecture
```mermaid
graph TB
ProvenanceSystem[Provenance System] --> Modes[Three Modes]
Modes --> None[None Mode<br/>Zero overhead]
Modes --> Proxy[Proxy Mode<br/>Runtime tracking]
Modes --> AST[AST Mode<br/>Compile-time]
ProvenanceSystem --> Policy[Policy Engine]
Policy --> BuiltIn[Built-in Policies]
Policy --> Custom[Custom Policies]
Policy --> Declarative[Declarative Policies]
Proxy --> ProxyAPI[createProvenanceProxy]
AST --> Compiler[instrumentCode]
Policy --> Actions[Policy Actions]
Actions --> Log[Log]
Actions --> Approve[Approve]
Actions --> Block[Block]
```
## Three Modes
### None Mode (Default)
No provenance tracking, zero overhead.
```typescript
// Default mode - no tracking
const user = { name: 'Alice', ssn: '123-45-6789' };
// Works normally with no overhead
```
### Proxy Mode
Runtime tracking with 5-10% overhead using JavaScript Proxies.
```typescript
import { createProvenanceProxy, ProvenanceSource } from '@mondaydotcomorg/atp-provenance';
const user = createProvenanceProxy(
{ name: 'Alice', ssn: '123-45-6789' },
{
type: ProvenanceSource.TOOL,
toolName: 'getUser',
apiGroup: 'users',
timestamp: Date.now(),
},
{
type: 'restricted',
readers: ['alice@company.com'],
}
);
// Provenance tracked automatically
console.log(user.name); // Proxy tracks access
```
### AST Mode
Compile-time instrumentation with 20-30% overhead, tracks primitive tainting.
```typescript
import { instrumentCode, createTrackingRuntime } from '@mondaydotcomorg/atp-provenance';
const { code } = instrumentCode(`
const user = await api.users.getUser({ id: '123' });
const email = user.email; // Taint propagates to email
await api.email.send({ to: 'external@company.com', body: email });
`);
const runtime = createTrackingRuntime();
// Execute instrumented code with runtime
```
## Security Policy Engine
### Quick Start
```typescript
import {
SecurityPolicyEngine,
preventDataExfiltration,
requireUserOrigin,
} from '@mondaydotcomorg/atp-provenance';
const policyEngine = new SecurityPolicyEngine(
[preventDataExfiltration, requireUserOrigin],
console // Logger (pino, winston, or console)
);
// Check before sensitive operations
try {
await policyEngine.checkTool('send', 'email', {
to: 'attacker@evil.com',
body: user, // Contains provenance metadata
});
} catch (error) {
console.error('Security policy blocked:', error.message);
}
```
### Built-in Policies
```typescript
import {
preventDataExfiltration, // Block data exfiltration
preventDataExfiltrationWithApproval, // Require approval for exfiltration
requireUserOrigin, // Require user-originated data
requireUserOriginWithApproval, // Require approval for non-user data
blockLLMRecipients, // Block LLM-extracted recipients
blockLLMRecipientsWithApproval, // Require approval for LLM recipients
auditSensitiveAccess, // Log all sensitive access
getBuiltInPolicies, // All block policies
getBuiltInPoliciesWithApproval, // All approval policies
} from '@mondaydotcomorg/atp-provenance';
```
### Declarative Policies (JSON Configuration)
Designed for security teams to define policies without writing code. Supports AWS IAM-style JSON configuration.
```typescript
import { createDeclarativePolicy, SecurityPolicyEngine } from '@mondaydotcomorg/atp-provenance';
const config = {
id: 'block-external-emails',
scope: { toolName: 'send' },
rules: [
{
action: 'block',
conditions: [
// Check argument value
{ field: 'args.to', operator: 'notEndsWith', value: '@company.com' },
// Check provenance of argument
{ field: 'provenance.args.body.source.type', operator: 'equals', value: 'user' },
],
reason: 'Cannot send internal user data to external email addresses',
},
],
};
const policy = createDeclarativePolicy(config);
const engine = new SecurityPolicyEngine([policy], console);
```
**JSON Schema Structure:**
```json
{
"policies": [
{
"id": "policy-id",
"scope": { "toolName": "^send.*" },
"rules": [
{
"action": "block", // or "approve", "log"
"conditions": [
{
"field": "args.param",
"operator": "equals", // equals, contains, startsWith, matches...
"value": "expected-value"
}
]
}
]
}
]
}
```
### Custom Policies (Code)
```typescript
import { createCustomPolicy, type SecurityPolicy } from '@mondaydotcomorg/atp-provenance';
const blockExternalAPIs: SecurityPolicy = createCustomPolicy({
name: 'blockExternalAPIs',
description: 'Block calls to external APIs',
check: async (toolName, apiGroup, args, metadata) => {
const externalAPIs = ['external-api', 'third-party'];
if (externalAPIs.includes(apiGroup)) {
return {
action: 'block',
reason: 'External API calls are not allowed',
};
}
return { action: 'approve' };
},
});
const engine = new SecurityPolicyEngine([blockExternalAPIs], console);
```
## Policy Actions
Policies can return three actions:
```typescript
type PolicyAction = 'log' | 'approve' | 'block';
interface PolicyResult {
action: PolicyAction;
reason?: string;
metadata?: Record<string, unknown>;
}
```
- **log**: Log the operation but allow it
- **approve**: Explicitly approve the operation
- **block**: Block the operation and throw error
## Provenance Metadata
### Track Data Sources
```typescript
import { ProvenanceSource } from '@mondaydotcomorg/atp-provenance';
enum ProvenanceSource {
USER = 0, // User-provided data
LLM = 1, // LLM-generated data
TOOL = 2, // Tool/API response
SYSTEM = 3, // System-generated data
}
interface ProvenanceMetadata {
source: SourceMetadata;
readers?: ReaderPermissions;
timestamp: number;
}
```
### Get Provenance
```typescript
import { getProvenance, hasProvenance } from '@mondaydotcomorg/atp-provenance';
const user = createProvenanceProxy(userData, source, readers);
// Check if object has provenance
if (hasProvenance(user)) {
const metadata = getProvenance(user);
console.log('Source:', metadata.source);
console.log('Readers:', metadata.readers);
}
```
## Pause/Resume Support
Provenance integrates with ATP's pause/resume mechanism:
```typescript
import {
captureProvenanceState,
restoreProvenanceState,
setProvenanceExecutionId,
cleanupProvenanceForExecution,
} from '@mondaydotcomorg/atp-provenance';
// Before execution
setProvenanceExecutionId('exec-123');
// Capture state before pause
const state = captureProvenanceState();
// Later, restore state on resume
restoreProvenanceState(state);
// Cleanup after execution
cleanupProvenanceForExecution('exec-123');
```
## Integration with ATP Server
```typescript
import { createServer, ProvenanceMode } from '@mondaydotcomorg/atp-server';
import { preventDataExfiltration, requireUserOrigin } from '@mondaydotcomorg/atp-server';
const server = createServer({
execution: {
provenanceMode: ProvenanceMode.PROXY, // or ProvenanceMode.AST
securityPolicies: [preventDataExfiltration, requireUserOrigin],
},
});
// All tool calls now enforce provenance policies
```
## Real-World Examples
### Prevent Data Exfiltration
```typescript
// User's sensitive data
const user = createProvenanceProxy(
{ name: 'Alice', ssn: '123-45-6789' },
{ type: ProvenanceSource.TOOL, toolName: 'getUser' },
{ type: 'restricted', readers: ['alice@company.com'] }
);
const engine = new SecurityPolicyEngine([preventDataExfiltration], console);
// This will throw - external email with restricted data
await engine.checkTool('send', 'email', {
to: 'attacker@evil.com',
body: user,
});
// ❌ Throws: ProvenanceSecurityError
// This will succeed - internal email
await engine.checkTool('send', 'email', {
to: 'alice@company.com',
body: user,
});
// ✅ Allowed
```
### Require User Origin
```typescript
// LLM-generated email address (untrusted)
const recipient = createProvenanceProxy(
'external@untrusted.com',
{ type: ProvenanceSource.LLM },
null
);
const engine = new SecurityPolicyEngine([requireUserOrigin], console);
// This will throw - LLM-generated recipient
await engine.checkTool('send', 'email', {
to: recipient,
subject: 'Hello',
});
// ❌ Throws: Non-user-originated data in sensitive field
// User-provided recipient (trusted)
const userRecipient = createProvenanceProxy(
'verified@company.com',
{ type: ProvenanceSource.USER },
null
);
await engine.checkTool('send', 'email', {
to: userRecipient,
subject: 'Hello',
});
// ✅ Allowed
```
### Approval Workflows
```typescript
import { preventDataExfiltrationWithApproval } from '@mondaydotcomorg/atp-provenance';
const engine = new SecurityPolicyEngine([preventDataExfiltrationWithApproval], console);
// Set approval callback
engine.setApprovalCallback(async (request) => {
console.log(`Approval needed: ${request.reason}`);
// In production: show UI, send to Slack, etc.
const approved = await getUserApproval(request);
return { approved };
});
// This will request approval instead of blocking
await engine.checkTool('send', 'email', {
to: 'external@company.com',
body: sensitiveData,
});
// → Calls approval callback
// → Proceeds if approved, blocks if denied
```
## Performance
| Mode | Overhead | Use Case |
| ----- | -------- | ----------------------------------- |
| None | 0% | No security requirements |
| Proxy | 5-10% | Production with moderate security |
| AST | 20-30% | Maximum security, tracks primitives |
## Primitive Taint Tracking (AST Mode)
```typescript
import {
markPrimitiveTainted,
isPrimitiveTainted,
getProvenanceForPrimitive,
} from '@mondaydotcomorg/atp-provenance';
// Mark primitive as tainted
markPrimitiveTainted('sensitive-string', metadata);
// Check if primitive is tainted
if (isPrimitiveTainted('sensitive-string')) {
const provenance = getProvenanceForPrimitive('sensitive-string');
console.log('String is tainted:', provenance);
}
```
## API Reference
### Core Functions
```typescript
createProvenanceProxy<T>(value: T, source: SourceMetadata, readers: ReaderPermissions): Proxied<T>
getProvenance(value: unknown): ProvenanceMetadata | null
hasProvenance(value: unknown): boolean
getAllProvenance(value: unknown): ProvenanceMetadata[]
canRead(metadata: ProvenanceMetadata, reader: string): boolean
```
### AST Mode
```typescript
instrumentCode(code: string): { code: string; metadata: unknown }
createTrackingRuntime(): Runtime
```
### Policy Engine
```typescript
new SecurityPolicyEngine(policies: SecurityPolicy[], logger: Logger)
engine.checkTool(toolName: string, apiGroup: string, args: unknown): Promise<void>
engine.setApprovalCallback(callback: ApprovalCallback): void
```
### Declarative Policies
```typescript
createDeclarativePolicy(config: DeclarativePolicyConfig): SecurityPolicy
loadDeclarativePolicies(config: PolicyConfiguration): SecurityPolicy[]
```
### State Management
```typescript
setProvenanceExecutionId(executionId: string): void
clearProvenanceExecutionId(): void
captureProvenanceState(): ProvenanceState
restoreProvenanceState(state: ProvenanceState): void
cleanupProvenanceForExecution(executionId: string): void
```
## TypeScript Support
Full TypeScript definitions with strict typing.
## Credits
Inspired by Google Research's CAMEL paper:
- Paper: [CAMEL: Capability-Aware Machine Execution Language](https://arxiv.org/abs/2410.02904)
- GitHub: https://github.com/google-research/camel-prompt-injection
## License
MIT