Provenance Tracking | Agent Tool Protocol
Skip to main content

Provenance Tracking

Provenance tracking in Agent Tool Protocol allows you to track where data comes from, where it goes, and enforce security policies on data flow. This is essential for compliance, security auditing, and preventing data leakage.

What is Provenance?​

Provenance is metadata that tracks the origin and history of data as it flows through your system. Every piece of data can carry information about:

  • Source: Where the data originated (API call, user input, LLM response)
  • Operations: What operations have been performed on it
  • Recipients: Where the data has been sent
  • Permissions: Who can read or modify the data

Enabling Provenance Tracking​

Basic Tracking​

import { createServer, ProvenanceMode } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.TRACK, // Enable tracking
},
});

Provenance Modes​

enum ProvenanceMode {
NONE = 'none', // No tracking (default, best performance)
TRACK = 'track', // Track provenance (recommended)
ENFORCE = 'enforce', // Track + enforce policies
}

How Provenance Works​

Automatic Tracking​

When provenance is enabled, every API call automatically tracks data origin:

// Code executed in sandbox
const user = await users.getUser({ userId: '123' });

// user object now has hidden provenance metadata:
// {
// source: {
// type: 'api',
// api: 'users',
// function: 'getUser',
// timestamp: 1234567890,
// },
// operations: [],
// recipients: [],
// }

Provenance Inheritance​

Data derived from tracked data inherits provenance:

const user = await users.getUser({ userId: '123' });
// user has provenance

const name = user.name;
// name inherits provenance from user

const greeting = `Hello, ${name}`;
// greeting inherits provenance

await llm.call({ prompt: greeting });
// Provenance system knows that user data is being sent to LLM

Manual Provenance Access​

You can access provenance metadata directly:

import { getProvenance, hasProvenance } from '@mondaydotcomorg/atp-provenance';

const user = await users.getUser({ userId: '123' });

if (hasProvenance(user)) {
const provenance = getProvenance(user);
console.log('Data source:', provenance.source);
console.log('Operations:', provenance.operations);
console.log('Recipients:', provenance.recipients);
}

Security Policies​

Built-in Policies​

Agent Tool Protocol provides several built-in security policies:

1. Prevent Data Exfiltration​

Block sensitive data from leaving your system:

import { preventDataExfiltration } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
preventDataExfiltration({
// Block data from these sources
sources: [
'users.getUser',
'payments.getTransaction',
'secrets.getAPIKey',
],
// From being sent to these recipients
recipients: [
'external-api',
'logging',
],
}),
],
},
});

Now if code tries to exfiltrate data:

// This will throw a SecurityViolation error
const user = await users.getUser({ userId: '123' });
await externalApi.sendData({ data: user }); // ❌ BLOCKED!

2. Require User Origin​

Ensure data comes from user input, not LLMs:

import { requireUserOrigin } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
requireUserOrigin({
// These APIs require user-originated data
apis: ['payments.makePayment', 'users.deleteUser'],
}),
],
},
});

Usage:

// This is OK - data comes from user input
const amount = getUserInput(); // User provides amount
await payments.makePayment({ amount }); // ✅ ALLOWED

// This is BLOCKED - data comes from LLM
const llmSuggestion = await llm.call({ prompt: "How much should I pay?" });
await payments.makePayment({ amount: llmSuggestion }); // ❌ BLOCKED!

3. Block LLM Recipients​

Prevent sensitive data from reaching LLMs:

import { blockLLMRecipients } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
blockLLMRecipients({
// Block data from these sources
sources: [
'users.getCreditCard',
'users.getSSN',
'secrets.getAPIKey',
],
}),
],
},
});

Usage:

// This will throw a SecurityViolation error
const creditCard = await users.getCreditCard({ userId: '123' });
await llm.call({ prompt: `Process payment: ${creditCard}` }); // ❌ BLOCKED!

4. Audit Sensitive Access​

Log access to sensitive data without blocking:

import { auditSensitiveAccess } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.TRACK,
securityPolicies: [
auditSensitiveAccess({
sources: ['users.getUser', 'payments.getTransaction'],
logger: (event) => {
console.log('Sensitive data accessed:', {
source: event.source,
recipient: event.recipient,
timestamp: event.timestamp,
executionId: event.executionId,
});

// Send to audit log service
auditService.log(event);
},
}),
],
},
});

Policies with Approval​

All policies support approval mode, which pauses execution for human approval:

import { preventDataExfiltrationWithApproval } from '@mondaydotcomorg/atp-server';

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
preventDataExfiltrationWithApproval({
sources: ['users.getUser'],
recipients: ['external-api'],
}),
],
},
});

When data exfiltration is detected:

// Execution pauses for approval
const user = await users.getUser({ userId: '123' });
await externalApi.sendData({ data: user }); // ⏸️ PAUSED FOR APPROVAL

// Client receives approval request
const result = await client.execute(code);
if (result.needsCallback?.type === 'approval') {
const approved = await showUserApprovalDialog(
result.needsCallback.payload.message
);

// Resume with approval result
await client.resume(result.executionId, { approved });
}

Custom Security Policies​

Creating Custom Policies​

You can create custom security policies:

import { createCustomPolicy } from '@mondaydotcomorg/atp-server';

const customPolicy = createCustomPolicy({
name: 'prevent-pii-logging',
description: 'Prevent PII from being logged',

// Called for every data operation
evaluate: (context) => {
const { source, recipient, data, provenance } = context;

// Check if data contains PII
const isPII = source?.api === 'users' &&
(source.function === 'getUser' ||
source.function === 'getUserProfile');

// Check if recipient is logging
const isLogging = recipient?.type === 'log';

if (isPII && isLogging) {
return {
action: 'deny',
reason: 'PII data cannot be logged',
};
}

return { action: 'allow' };
},
});

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [customPolicy],
},
});

Advanced Policy Example​

const gdprCompliancePolicy = createCustomPolicy({
name: 'gdpr-compliance',
description: 'Enforce GDPR compliance rules',

evaluate: (context) => {
const { source, recipient, data, provenance } = context;

// Check if data is EU user data
const isEUUserData = provenance?.tags?.includes('eu-user-data');

// Check if recipient is outside EU
const isNonEURecipient = recipient?.tags?.includes('non-eu-system');

if (isEUUserData && isNonEURecipient) {
// Check for user consent
const hasConsent = provenance?.metadata?.consent === true;

if (!hasConsent) {
return {
action: 'deny',
reason: 'EU user data cannot be transferred outside EU without consent',
suggestion: 'Obtain user consent first',
};
}
}

// Check data retention policies
const retentionDays = provenance?.metadata?.retentionDays || 90;
const dataAge = Date.now() - provenance.timestamp;
const maxAge = retentionDays * 24 * 60 * 60 * 1000;

if (dataAge > maxAge) {
return {
action: 'deny',
reason: `Data retention period exceeded (${retentionDays} days)`,
};
}

return { action: 'allow' };
},
});

Tagging Data​

Adding Tags​

You can add custom tags to provenance metadata:

server.registerAPI('users', {
getEUUser: {
description: 'Get EU user data',
inputSchema: { /* ... */ },
handler: async ({ userId }) => {
const user = await database.users.findOne({ userId });

// Mark data with custom tags
return markWithProvenance(user, {
tags: ['eu-user-data', 'pii', 'gdpr-protected'],
metadata: {
retentionDays: 90,
consentRequired: true,
},
});
},
},
});

Using Tags in Policies​

const policy = createCustomPolicy({
name: 'tag-based-policy',
evaluate: (context) => {
const { provenance } = context;

// Block operations on data with specific tags
if (provenance?.tags?.includes('confidential')) {
return {
action: 'deny',
reason: 'Confidential data cannot be processed',
};
}

return { action: 'allow' };
},
});

Reader Permissions​

Control who can read data:

import { markWithProvenance } from '@mondaydotcomorg/atp-provenance';

const sensitiveData = {
secret: 'my-secret',
};

// Only admin role can read this data
const protectedData = markWithProvenance(sensitiveData, {
readerPermissions: {
roles: ['admin'],
users: ['user-123'],
},
});

// Later, when code tries to read this data:
// The policy engine checks if current user has permission

Provenance State Management​

Capturing State​

Capture provenance state for later restoration:

import { captureProvenanceState, restoreProvenanceState } from '@mondaydotcomorg/atp-provenance';

// Capture current provenance state
const state = captureProvenanceState();

// Perform operations that modify provenance
const user = await users.getUser({ userId: '123' });

// Restore previous state
restoreProvenanceState(state);

Execution Cleanup​

Provenance data is automatically cleaned up after execution:

// After each execution, provenance data is cleared
// This prevents memory leaks and ensures isolation

Best Practices​

1. Choose the Right Mode​

// Development: TRACK mode for debugging
const devServer = createServer({
execution: {
provenanceMode: ProvenanceMode.TRACK,
},
});

// Production: ENFORCE mode for security
const prodServer = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
preventDataExfiltration(/* ... */),
blockLLMRecipients(/* ... */),
],
},
});

2. Layer Security Policies​

Use multiple policies for defense-in-depth:

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
// Layer 1: Prevent data exfiltration
preventDataExfiltration({
sources: ['users.*', 'payments.*'],
recipients: ['external-*'],
}),

// Layer 2: Block LLM access to sensitive data
blockLLMRecipients({
sources: ['secrets.*', 'auth.*'],
}),

// Layer 3: Require user origin for sensitive operations
requireUserOrigin({
apis: ['payments.makePayment', 'users.deleteUser'],
}),

// Layer 4: Audit all access
auditSensitiveAccess({
sources: ['*'],
logger: auditLogger,
}),
],
},
});

3. Tag Sensitive Data​

Always tag sensitive data at the source:

server.registerAPI('database', {
getUserCreditCard: {
description: 'Get user credit card',
handler: async ({ userId }) => {
const card = await db.creditCards.findOne({ userId });

return markWithProvenance(card, {
tags: ['pii', 'financial', 'pci-dss'],
sensitivityLevel: 'high',
retentionDays: 7,
});
},
},
});

4. Use Approval for High-Risk Operations​

// Allow high-risk operations with approval
const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
requireUserOriginWithApproval({
apis: ['payments.makePayment'],
}),
],
},
});

5. Monitor and Alert​

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
auditSensitiveAccess({
sources: ['users.getUser'],
logger: (event) => {
// Alert on suspicious patterns
if (event.source.executionCount > 100) {
alertSecurityTeam('Potential data scraping detected', event);
}

// Log to SIEM
siemService.log(event);
},
}),
],
},
});

Performance Considerations​

Impact of Provenance Tracking​

ModePerformance ImpactUse Case
NONENone (0%)Development, non-sensitive data
TRACKLow (5-10%)Production with auditing
ENFORCEMedium (10-20%)Production with active security

Optimization Tips​

  1. Use NONE mode in development if not testing security
  2. Cache provenance checks for repeated operations
  3. Batch provenance operations when possible
  4. Use specific source patterns instead of wildcards

Debugging Provenance​

Enable Debug Logging​

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.TRACK,
},
logger: 'debug',
});

Inspect Provenance in Code​

import { getAllProvenance } from '@mondaydotcomorg/atp-provenance';

// Get all provenance metadata for debugging
const allProvenance = getAllProvenance();
console.log('Provenance graph:', allProvenance);

Next Steps​

Common Use Cases​

1. Preventing Credit Card Leakage​

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
blockLLMRecipients({
sources: ['payments.getCreditCard'],
}),
preventDataExfiltration({
sources: ['payments.getCreditCard'],
recipients: ['external-*', 'logging.*'],
}),
],
},
});

2. GDPR Compliance​

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
gdprCompliancePolicy, // Custom policy (see above)
auditSensitiveAccess({
sources: ['users.*'],
logger: gdprAuditLogger,
}),
],
},
});

3. PCI-DSS Compliance​

const server = createServer({
execution: {
provenanceMode: ProvenanceMode.ENFORCE,
securityPolicies: [
preventDataExfiltration({
sources: ['payments.*'],
recipients: ['external-*'],
}),
requireUserOriginWithApproval({
apis: ['payments.makePayment'],
}),
auditSensitiveAccess({
sources: ['payments.*'],
logger: pciAuditLogger,
}),
],
},
});
Agent Tool Protocol | ATP - Code Execution for AI Agents