| name | openevidence-security-basics |
| description | Apply OpenEvidence security best practices for HIPAA compliance and PHI protection.
Use when securing API keys, implementing PHI handling,
or auditing OpenEvidence security configuration.
Trigger with phrases like "openevidence security", "openevidence hipaa",
"openevidence phi", "secure openevidence", "openevidence compliance".
|
| allowed-tools | Read, Write, Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
OpenEvidence Security Basics
Overview
Security best practices for OpenEvidence integrations handling Protected Health Information (PHI) in compliance with HIPAA regulations.
Prerequisites
- OpenEvidence SDK installed
- Understanding of HIPAA requirements
- Signed Business Associate Agreement (BAA)
- Access to organization security policies
OpenEvidence Security Certifications
- SOC 2 Type II certified
- HIPAA compliant
- AES-256 encryption at rest
- TLS 1.2+ encryption in transit
- Google Cloud Platform hosted
Instructions
Step 1: Secure Credential Management
OPENEVIDENCE_API_KEY=oe_live_***
OPENEVIDENCE_ORG_ID=org_***
OPENEVIDENCE_WEBHOOK_SECRET=whsec_***
.env
.env.local
.env.*.local
*.pem
*.key
credentials*.json
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
const client = new SecretManagerServiceClient();
export async function getOpenEvidenceCredentials(): Promise<{
apiKey: string;
orgId: string;
}> {
const [apiKeyVersion] = await client.accessSecretVersion({
name: 'projects/my-project/secrets/openevidence-api-key/versions/latest',
});
const [orgIdVersion] = await client.accessSecretVersion({
name: 'projects/my-project/secrets/openevidence-org-id/versions/latest',
});
return {
apiKey: apiKeyVersion.payload!.data!.toString(),
orgId: orgIdVersion.payload!.data!.toString(),
};
}
Step 2: PHI Handling - Input Sanitization
interface SanitizedQuery {
question: string;
context: {
ageRange?: string;
sex?: string;
conditionCategories?: string[];
};
}
export function sanitizeQueryForOpenEvidence(
question: string,
patientContext?: PatientContext
): SanitizedQuery {
let sanitized = question;
sanitized = sanitized.replace(/\b(Mr\.|Mrs\.|Ms\.|Dr\.)\s+[A-Z][a-z]+\b/g, '[PATIENT]');
sanitized = sanitized.replace(/\b\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}\b/g, '[DATE]');
sanitized = sanitized.replace(/\bMRN[:\s]*\d+\b/gi, '[MRN]');
sanitized = sanitized.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]');
return {
question: sanitized,
context: patientContext ? {
: (patientContext.),
: patientContext.,
: (patientContext.),
} : ,
};
}
(): | {
(!age) ;
(age < ) ;
(age < ) ;
(age < ) ;
(age < ) ;
;
}
(): [] | {
: <, > = {
: ,
: ,
: ,
};
conditions?.( categoryMap[c.()] || );
}
Step 3: Audit Logging (HIPAA Required)
interface AuditEntry {
timestamp: Date;
eventType: 'query' | 'deepconsult' | 'access' | 'export';
userId: string;
userRole: string;
action: string;
resourceType: 'clinical_answer' | 'research_report';
resourceId?: string;
ipAddress: string;
userAgent: string;
success: boolean;
errorCode?: string;
}
export class HIPAAAuditLogger {
private logStore: AuditLogStore;
constructor(store: AuditLogStore) {
this.logStore = store;
}
async logClinicalQuery(
userId: string,
userRole: string,
queryId: string,
success: boolean,
:
): <> {
..({
: (),
: ,
userId,
userRole,
: ,
: ,
: queryId,
: .(request),
: request..() || ,
success,
});
}
(
: ,
: ,
: ,
: ,
:
): <> {
..({
: (),
: ,
userId,
userRole,
: ,
: ,
: consultId,
: .(request),
: request..() || ,
success,
});
}
(: ): {
forwarded = request..();
(forwarded) forwarded.()[].();
;
}
}
Step 4: Webhook Signature Verification
import crypto from 'crypto';
export function verifyWebhookSignature(
payload: string | Buffer,
signature: string,
secret: string,
tolerance: number = 300
): boolean {
const parts = signature.split(',').reduce((acc, part) => {
const [key, value] = part.split('=');
acc[key] = value;
return acc;
}, {} as Record<string, string>);
const timestamp = parseInt(parts['t']);
const providedSignature = parts['v1'];
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - timestamp) > tolerance) {
.();
;
}
signedPayload = ;
expectedSignature = crypto
.(, secret)
.(signedPayload)
.();
{
crypto.(
.(providedSignature),
.(expectedSignature)
);
} {
;
}
}
Step 5: Data Retention Compliance
interface RetentionPolicy {
auditLogs: number;
queryResults: number;
deepConsultReports: number;
}
const HIPAA_RETENTION: RetentionPolicy = {
auditLogs: 2190,
queryResults: 0,
deepConsultReports: 365,
};
export class DataRetentionManager {
constructor(private policy: RetentionPolicy = HIPAA_RETENTION) {}
async cleanupExpiredData(): Promise<CleanupReport> {
const cutoffs = {
auditLogs: new Date(Date.now() - this.policy.auditLogs * 24 * 60 * 60 * 1000),
: (.() - .. * * * * ),
};
archivedLogs = db..({
: { : { : cutoffs. } },
});
deletedReports = db..({
: { : { : cutoffs. } },
});
{
: archivedLogs.,
: deletedReports.,
: (),
};
}
}
Security Checklist
Output
- Secure credential management
- PHI sanitization layer
- HIPAA-compliant audit logging
- Webhook signature verification
- Data retention compliance
Error Handling
| Security Issue | Detection | Mitigation |
|---|
| Exposed API key | Git scanning alert | Rotate immediately, audit access |
| PHI in query | Log pattern matching | Block request, alert compliance |
| Failed signature | Webhook verification | Reject webhook, alert security |
| Unauthorized access | Audit log review | Revoke access, investigate |
Examples
Secure Query Service
const auditLogger = new HIPAAAuditLogger(auditStore);
export async function secureClinicaQuery(
question: string,
patientContext: PatientContext | undefined,
user: AuthenticatedUser,
request: Request
): Promise<ClinicalResponse> {
const sanitized = sanitizeQueryForOpenEvidence(question, patientContext);
const response = await client.query({
question: sanitized.question,
context: {
specialty: 'internal-medicine',
urgency: 'routine',
...sanitized.context,
},
});
await auditLogger.logClinicalQuery(
user.id,
user.role,
response.id,
true,
request
);
return response;
}
Resources
Next Steps
For production deployment, see openevidence-prod-checklist.