This document provides a comprehensive security analysis of the Pega Case Management Browser Agent, covering threat models, data protection mechanisms, compliance considerations, and security best practices.
Version: 1.0.0
Last Updated: 2025-05-10
Security Classification: Confidential
┌─────────────────────────────────────────────────────────────┐
│ Browser Extension │
├─────────────────────────────────────────────────────────────┤
│ Content Scripts │ Service Worker │ Side Panel │
│ (Isolated Context) │ (Trusted Boundary)│ (UI Layer) │
│ │ │ │
│ • PII Masking │ • Session Store │ • Display │
│ • DOM Observation │ • Audit Logging │ • User Input │
│ • Token Resolution │ • LLM Calls │ • Confirmation│
└─────────────────────────────────────────────────────────────┘
│
▼
┌──────────────┐
│ LLM API │
│ (External) │
└──────────────┘
- Data Exfiltration: Unauthorized transmission of sensitive PII
- Credential Theft: Access to Pega authentication tokens
- Prompt Injection: Malicious input compromising LLM behavior
- Session Hijacking: Unauthorized access to user sessions
- Audit Tampering: Modification or deletion of audit trails
- Authorization Bypass: Executing actions beyond user permissions
- Confidentiality: Protect PII through tokenization and masking
- Integrity: Ensure audit trail immutability and action validation
- Availability: Maintain service continuity without exposing data
- Accountability: Track all actions with comprehensive audit logging
- Privacy: Never transmit raw PII or authentication credentials externally
The agent classifies and protects 8 categories of Personally Identifiable Information:
| Category | Description | Example Patterns |
|---|---|---|
| NAME | Full names, first/last names | first_name, customer_name, insured_name |
| SSN | Social Security Numbers, Tax IDs | ssn, tax_id, ein, national_id |
| DOB | Dates of Birth | date_of_birth, dob, birth_date |
| Email addresses | email, email_address |
|
| PHONE | Phone numbers, fax | phone, mobile, cell, contact_number |
| ACCOUNT | Account numbers, credit cards | account_num, credit_card, policy_num |
| ADDRESS | Street addresses, locations | address, street, city, state, zip |
| INCOME | Financial information | income, salary, annual_income |
Location: src/content-scripts/pii-masker.ts
classify(label: string | null, testId: string | null): PiiCategory {
const combined = `${label ?? ''} ${testId ?? ''}`.toLowerCase();
for (const [category, patterns] of Object.entries(PII_PATTERNS)) {
for (const pattern of patterns) {
if (pattern.test(combined)) {
return category as PiiCategory;
}
}
}
return null;
}Classification Strategy:
- Pattern matching on field labels and test IDs
- Case-insensitive regex matching
- Combined label + testId analysis
- Returns null for non-PII fields
{CATEGORY_COUNTER}
Examples:
{NAME_1}→ "John Smith"{SSN_1}→ "123-45-6789"{EMAIL_2}→ "user@example.com"
mask(value: string | null, category: PiiCategory): string | null {
if (!this.shouldMask(category)) {
return value; // Not masking this category
}
// Check for existing token
for (const [token, existingValue] of categoryMap.entries()) {
if (existingValue === value) {
return token; // Reuse token for same value
}
}
// Create new token
const token = `{${category}_${counter}}`;
categoryMap.set(token, value);
return token;
}┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ DOM Field │ -> │ PII Masker │ -> │ Token Map │
│ "John" │ │ {NAME_1} │ │ (Memory) │
└─────────────┘ └──────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ LLM Request │
│ {NAME_1} │
└─────────────┘
│
▼
┌─────────────┐
│ LLM Response│
│ "Update │
│ {NAME_1}" │
└─────────────┘
│
▼
┌─────────────┐
│ Resolution │
│ "Update │
│ John" │
└─────────────┘
Key Properties:
- In-Memory Only: Token maps never persisted to disk
- Session Isolated: Separate token map per browser tab
- Deterministic: Same value always gets same token
- Reversible: Tokens resolved only at action execution time
- Auto-Cleanup: Maps cleared on tab/session close
Each browser tab maintains its own isolated token map:
class PIIMasker {
private tokenMaps: Map<string, Map<string, string>> = new Map();
clearSession(): void {
this.tokenMaps.clear();
this.counters.clear();
}
}Isolation Guarantees:
- Token maps never shared across tabs
- Session closure automatically clears maps
- No persistence in chrome.storage
- No cross-tab token resolution
PII masking is enforced at 4 critical checkpoints:
-
DOM Snapshot Creation (
dom-observer.ts)const maskedFields = piiMasker.maskFields(parsedFields);
-
LLM Request Preparation (
service-worker/llm-client.ts)const maskedContext = maskPII(context);
-
Audit Logging (
shared/audit-logger.ts)// Never logs raw PII, only tokens logCommandReceived(command: string, caseId: string | null)
-
Storage Operations (
service-worker/session-store.ts)// chrome.storage.session contains only masked tokens
✅ SAFE to Transmit:
- PII tokens (
{NAME_1},{SSN_2}, etc.) - Masked field values
- Case IDs and metadata
- Intent classifications
- Action plans (with tokens)
- Audit entries (with tokens)
❌ NEVER Transmitted:
- Raw PII values (names, SSNs, emails, etc.)
- Pega authentication tokens
- Session cookies
- Passwords
- Unmasked field values
- Full DOM snapshots
✅ Browser-Local Only:
- Token → PII mappings (in-memory only)
- Pega authentication credentials
- Session state
- Raw DOM snapshots
- User preferences
User Input (Plain)
│
▼
┌─────────────────────────────────────────────────────┐
│ Content Script: PII Masker │
│ "John Smith" → "{NAME_1}" │
└─────────────────────────────────────────────────────┘
│
│ Masked Data Only
▼
┌─────────────────────────────────────────────────────┐
│ Service Worker: Session Store │
│ chrome.storage.session (tokens only) │
└─────────────────────────────────────────────────────┘
│
│ Masked Data Only
▼
┌─────────────────────────────────────────────────────┐
│ LLM API Request │
│ "Update {NAME_1} to {NAME_2}" │
└─────────────────────────────────────────────────────┘
│
│ Masked Response
▼
┌─────────────────────────────────────────────────────┐
│ Content Script: Token Resolution │
│ "{NAME_1}" → "John Smith" │
└─────────────────────────────────────────────────────┘
│
▼
DOM Execution (Plain Values)
- First-Line Defense: PII Masker runs before any external transmission
- No Bypass: All data paths pass through masker
- Fail-Safe: Masking errors default to masking
- Audit Verification: Audit logs verify masking occurred
Location: manifest.json
{
"manifest_version": 3,
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
},
"permissions": [
"activeTab",
"scripting",
"storage",
"sidePanel"
],
"host_permissions": ["<all_urls>"]
}Security Hardening:
-
CSP Restrictions
- No remote code execution
- No eval() (except WASM)
- No inline scripts
- Same-origin policy enforced
-
Minimal Permissions
activeTab: Only active tab accessscripting: Dynamic script injectionstorage: Extension storage onlysidePanel: UI rendering
-
Host Permissions
<all_urls>: Required for Pega detection- No special API access (webRequest, etc.)
Trusted Boundary:
- All message routing passes through service worker
- No direct content script ↔ LLM communication
- Service worker validates all messages
- Type-safe message protocol (
message-types.ts)
// Type-safe message validation
export function isValidMessage(message: unknown): message is Message {
if (!message || typeof message !== 'object') return false;
const msg = message as Partial<Message>;
if (!msg.type || !Object.values(MessageType).includes(msg.type)) {
return false;
}
return true;
}Explicitly NOT Accessed:
- Pega authentication cookies
- Authorization headers
- Session tokens
- Login credentials
Architecture Decision: The extension operates as a client-side assistant only. It:
- Reads visible DOM data
- Interacts with form fields
- Never accesses Pega backend APIs
- Never sees authentication tokens
Storage Location: chrome.storage.local (encrypted by Chrome)
// Enterprise configuration with API keys
interface LLMConfig {
provider: LLMProvider;
endpoint: string;
model: string;
apiKey?: string; // Stored securely in chrome.storage.local
}Security Properties:
- Keys never logged or transmitted in plain text
- Keys isolated per extension instance
- Keys accessible only to service worker
- No key exposure to content scripts
Supported Providers:
- Azure OpenAI
- OpenAI
- Anthropic
- Mistral
- Local models
Authentication Flow:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Enterprise │ -> │ chrome.storage│ -> │ LLM API │
│ Config │ │ .local │ │ Request │
│ (API Key) │ │ (Encrypted) │ │ (Bearer) │
└──────────────┘ └──────────────┘ └──────────────┘
Defensive Measures:
-
Input Sanitization
// Sanitize user commands before LLM const sanitized = command .replace(/<script>/gi, '') .replace(/javascript:/gi, '') .substring(0, 5000); // Length limit
-
Structured Prompts
- System prompts hardcoded
- User input clearly delimited
- No prompt concatenation
-
Output Validation
- Parse LLM response as JSON
- Validate against schema
- Reject malformed responses
- Type-safe action plan parsing
-
Instruction Injection Prevention
// Never execute arbitrary code from LLM // Only execute validated ActionPlan steps if (isValidActionPlan(llmResponse)) { await executePlan(llmResponse); } else { throw new PlanParseError('Invalid LLM response'); }
Validation Layers:
-
Schema Validation
interface ActionPlan { planId: string; intent: IntentType; summary: string; steps: PlanStep[]; expectedOutcome: string; }
-
Type Guards
function isValidActionPlan(obj: unknown): obj is ActionPlan { // Runtime type checking return ( typeof obj === 'object' && 'planId' in obj && 'steps' in obj && Array.isArray(obj.steps) ); }
-
Selector Validation
// Validate CSS selectors before execution try { document.querySelector(step.selector); } catch { throw new SelectorNotFoundError(step.selector); }
-
Action Restrictions
- Only whitelisted action types
- No arbitrary JavaScript execution
- No native alerts or confirm dialogs
- No access to chrome.* APIs from content scripts
Location: src/shared/audit-logger.ts
Event Types:
type AuditEventType =
| 'PEGA_DETECTED'
| 'CASE_OPENED'
| 'SUMMARY_GENERATED'
| 'COMMAND_RECEIVED'
| 'INTENT_CLASSIFIED'
| 'PLAN_GENERATED'
| 'PLAN_CONFIRMED'
| 'PLAN_CANCELLED'
| 'PLAN_EXECUTED'
| 'PLAN_STEP_FAILED'
| 'FEEDBACK_RECEIVED';Audit Entry Structure:
interface AuditEntry {
entryId: string;
timestamp: string;
sessionId: string;
userId: string | null;
caseId: string | null;
eventType: string;
intent: IntentType | null;
planSummary: string | null; // Masked
stepCount: number | null;
outcome: OutcomeType | null;
errorMessage: string | null;
}Example Audit Entry:
{
"entryId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-05-10T14:30:00.000Z",
"sessionId": "session-123",
"userId": null,
"caseId": "CASE-123",
"eventType": "PLAN_EXECUTED",
"intent": "UPDATE_FIELD",
"planSummary": "Update {NAME_1} to {NAME_2}",
"stepCount": 3,
"outcome": "success",
"errorMessage": null
}Storage Locations:
- In-Memory: Last 500 entries (FIFO eviction)
- chrome.storage.session: Cleared on browser close
- Backend (Optional): Configurable endpoint
Retention:
- Default: 500 entries per session
- Max entries: Configurable via
maxEntries - Session-scoped: Auto-clears on browser close
- No long-term storage in extension
Read Access:
- Service worker only
- No content script access
- User can view via extension UI
Write Access:
- Service worker only
- Immutable once written
- No delete API (only clear all)
Transmission:
- Optional backend sync
- Requires auth token
- Never includes raw PII
Protected Health Information (PHI):
- The extension may access PHI in Pega case fields
- PHI is classified as PII and tokenized
- Tokens never transmitted with raw values
HIPAA Safeguards:
-
Administrative Safeguards
- Audit logging for all PHI access
- Session tracking for user actions
- Configurable role-based access
-
Physical Safeguards
- Data stays in user's browser
- No cloud storage of raw PHI
- In-memory token maps only
-
Technical Safeguards
- PII tokenization before transmission
- No Pega auth access
- Encrypted storage (Chrome-managed)
HIPAA Recommendations:
- Enable audit logging for healthcare deployments
- Use
localProcessingOnly: truefor PHI workloads - Implement custom backend for audit trail retention
- Configure role restrictions for PHI access
Data Subject Rights:
-
Right to Access
- Users can view audit logs via extension UI
- Export functionality for session data
-
Right to Erasure
- Clear session data on browser close
- Manual clear via extension settings
- No long-term data retention
-
Right to Rectification
- Token maps cleared on session end
- No persistent PII storage
-
Right to Portability
- Audit logs exportable (JSON format)
- Session data exportable
GDPR Safeguards:
- Data minimization (only PII transmitted as tokens)
- Purpose limitation (LLM processing only)
- Storage limitation (session-scoped only)
- Integrity and confidentiality (tokenization)
Security Configuration:
interface SecurityConfig {
piiMaskingEnabled: boolean; // Always true
piiCategoriesToMask: string[]; // All 8 categories
localProcessingOnly: boolean; // For PHI/PCI
allowedLLMProviders: string[]; // Whitelist
auditLoggingEnabled: boolean; // Always true
requireConfirmationForAllActions: boolean;
disabledCapabilities: IntentType[]; // Role restrictions
}Enterprise Recommendations:
-
For Healthcare (HIPAA)
{ "piiMaskingEnabled": true, "localProcessingOnly": true, "auditLoggingEnabled": true, "allowedLLMProviders": ["azure-openai"], "requireConfirmationForAllActions": true } -
For Finance (PCI)
{ "piiCategoriesToMask": ["ACCOUNT", "SSN", "NAME", "DOB"], "auditLoggingEnabled": true, "requireConfirmationForAllActions": true, "disabledCapabilities": ["DELETE", "ESCALATE"] } -
For Government (FedRAMP)
{ "allowedLLMProviders": ["azure-openai"], "auditLoggingEnabled": true, "piiMaskingEnabled": true, "requireConfirmationForAllActions": true }
Production Deployment:
const enterpriseConfig: EnterpriseConfig = {
version: "1.0.0",
security: {
piiMaskingEnabled: true,
piiCategoriesToMask: ["NAME", "SSN", "DOB", "EMAIL", "PHONE", "ACCOUNT", "ADDRESS", "INCOME"],
localProcessingOnly: false, // Set to true for PHI
allowedLLMProviders: ["azure-openai", "anthropic"],
auditLoggingEnabled: true,
requireConfirmationForAllActions: true,
disabledCapabilities: []
},
llm: {
provider: "azure-openai",
endpoint: "https://your-instance.openai.azure.com",
model: "gpt-4",
maxTokens: 2000,
temperature: 0.7
},
pega: {
targetDomains: ["*.pega.com", "your-domain.com"],
useDirectAPI: false
},
roleRestrictions: {
"caseworker": ["*"],
"manager": ["*"],
"viewer": ["SUMMARIZE_CASE", "SHOW_QUEUE", "EXPLAIN"]
}
};DO:
✅ Enable PII masking for all deployments
✅ Use Azure OpenAI for enterprise deployments
✅ Enable audit logging
✅ Require confirmation for destructive actions
✅ Configure role-based access control
✅ Use HTTPS for all API endpoints
✅ Review audit logs regularly
✅ Implement rate limiting for LLM calls
✅ Test token resolution before deployment
✅ Keep extension updated
DON'T:
❌ Disable PII masking
❌ Transmit raw PII to LLMs
❌ Store API keys in source code
❌ Use eval() or dynamic code execution
❌ Access Pega authentication tokens
❌ Log sensitive data in plain text
❌ Disable audit logging in production
❌ Use untrusted LLM providers
❌ Share token maps across sessions
❌ Expose service worker to content scripts
Security Incident Categories:
-
PII Exposure
- Symptoms: Raw PII in logs or LLM requests
- Response: Immediately disable extension
- Investigation: Check masking configuration
- Prevention: Review masking patterns
-
Unauthorized Actions
- Symptoms: Actions executed without user consent
- Response: Disable auto-confirmation
- Investigation: Review audit logs
- Prevention: Enable confirmations
-
API Key Compromise
- Symptoms: Unexpected LLM usage
- Response: Rotate API keys
- Investigation: Check chrome.storage.local
- Prevention: Use key management service
-
Audit Trail Tampering
- Symptoms: Missing audit entries
- Response: Enable backend sync
- Investigation: Check storage quotas
- Prevention: Monitor audit logs
Incident Response Plan:
1. Detection → Audit log review, user reports
2. Containment → Disable extension, rotate keys
3. Eradication → Patch vulnerabilities
4. Recovery → Restore from known good state
5. Lessons Learned → Update security docs
PII Masking Tests: tests/unit/pii-masker.test.ts
- Classification accuracy
- Token generation uniqueness
- Token resolution correctness
- Session isolation
Intent Classification Tests: tests/unit/intent-classifier.test.ts
- Prompt injection resistance
- Input validation
- Output sanitization
Security Test Cases:
describe('PII Masking', () => {
it('should mask all 8 PII categories', () => {
const categories = ['NAME', 'SSN', 'DOB', 'EMAIL', 'PHONE', 'ACCOUNT', 'ADDRESS', 'INCOME'];
categories.forEach(category => {
expect(masker.classify(category, category)).toBe(category);
});
});
it('should generate unique tokens per value', () => {
const token1 = masker.mask('John', 'NAME');
const token2 = masker.mask('Jane', 'NAME');
expect(token1).not.toBe(token2);
});
it('should reuse tokens for same value', () => {
const token1 = masker.mask('John', 'NAME');
const token2 = masker.mask('John', 'NAME');
expect(token1).toBe(token2);
});
});Recommended Test Scenarios:
-
PII Extraction
- Attempt to extract raw PII from LLM responses
- Try to bypass tokenization
- Test token resolution exploits
-
Prompt Injection
- Inject system prompts in user commands
- Attempt to expose system context
- Try to manipulate action plans
-
Authorization Bypass
- Attempt actions outside role permissions
- Test confirmation bypasses
- Try to execute disabled capabilities
-
Data Exfiltration
- Monitor network traffic for PII
- Check chrome.storage for raw data
- Verify no PII in audit logs
- Static Analysis: ESLint security plugins
- Dependency Scanning: npm audit
- Penetration Testing: OWASP ZAP
- Code Review: Manual security reviews
- PII masking enabled for all 8 categories
- Audit logging enabled and configured
- API keys stored in chrome.storage.local
- Role-based access control configured
- HTTPS only for all endpoints
- Rate limiting configured for LLM calls
- Confirmation required for destructive actions
- Token resolution tested in target environment
- Audit log retention policy defined
- Incident response plan documented
- Security training completed for developers
- Penetration testing performed
- Compliance review completed (HIPAA/GDPR)
Security Questions: security@example.com
Vulnerability Reporting: Please use responsible disclosure
Documentation: https://github.com/your-org/pega-agent
Document Classification: Confidential
Distribution: Need-to-know basis only
Version Control: Maintained in git repository
Review Cycle: Quarterly or after security incidents
This security document is a living document. Please report any security concerns or suggestions to the security team immediately.