Skip to content
Security & Privacy

Architected for the AppExchange Security Review.

CIO Pipelines is built to clear the Salesforce AppExchange Security Review and to be deployable to security-sensitive enterprise orgs. The package source is auditable end-to-end.

CRUD / FLS enforcement

  • All SOQL queries in @AuraEnabled methods use WITH SECURITY_ENFORCED
  • All DML operations in controllers are gated by isCreateable(), isUpdateable(), isDeletable() checks
  • CIO_SchemaHelper validates isAccessible() before returning objects/fields to the UI
  • Subquery and relationship-traversal queries catch QueryException and degrade gracefully when the running user is missing FLS

Sharing model

  • All controller classes use with sharing (respects org-wide defaults and sharing rules)
  • Service classes that run in async context use inherited sharing
  • No class uses without sharing

SOQL injection prevention

  • Admin-supplied filter text on CIO_Scheduled_Sync__c.SOQL_Filter__c is parsed and validated by CIO_SoqlFilterValidator before execution. Strict whitelist grammar — only safe operators, validated field names, escaped string literals, no sub-SELECTs, no comments, no semicolons.
  • CIO_RecruiterDashboardService resolves the configurable owner field against a cached schema-validated allowlist; native SOQL with bind variables is dispatched over the canonical name returned by Schema.SObjectField.getDescribe().getName().
  • CIO_SourceConfigController.saveSourceMappings deletes existing mappings via a hardcoded switch over the five legitimate lookup-field branches — never via dynamic Database.query.
  • All other dynamic SOQL uses bind variables; user-supplied values are never string-concatenated.

API key security

  • API_Key__c (Pipelines CDP write key) and App_API_Key__c (App API bearer token) are EncryptedText fields. Salesforce encrypts them at rest with platform encryption.
  • Subscriber-org users see the masked form (*****) unless they have "View Encrypted Data" permission.
  • The Settings UI returns a fully-asterisk-masked value to the LWC; the unmasked key is never sent over the wire to the browser.
  • CIO_SettingsController.saveSettings only updates the stored key when the submitted value does not contain * — i.e. the admin actually re-typed a new key.
  • API keys are scrubbed from any persisted activity-log body via CIO_Logger.sanitizeBody().

Future migration to External Credentials

The package ships today with EncryptedText storage because that pattern is well-supported in 2GP managed packages. A future release will introduce External Credentials so that the auth header is injected by the platform and Apex never reads the key directly.

Webhook security

  • Inbound webhooks at /services/apexrest/cio/webhook/* verify HMAC-SHA256 signatures using a per-config secret stored on CIO_Webhook_Config__c.Secret_Key__c.
  • Signature comparison is constant-time (CIO_WebhookReceiver.constantTimeBlobEquals) to defeat timing-side-channel attacks.
  • Malformed signatures are rejected without echoing parser errors back to the caller.
  • Internal exceptions never leak to the response body — handler returns a generic {"error": "Internal server error"} and logs detail server-side.
  • All response bodies are built with JSON.serialize(Map<String, Object>), never with string concatenation.

Data retention & PII handling

  • CIO_Activity_Log__c retention is governed by Log_Body_Retention_Days__c (default 30 days, minimum 7).
  • The daily CIO_LogPurgeBatch (Schedulable) deletes records older than the cutoff.
  • Set Log_Bodies_Enabled__c = false to skip body capture entirely. The log row is still created (operational visibility) but bodies are null.
  • The on-demand purge endpoint enforces a 7-day floor, requires isDeletable() on the log object, and writes an audit record before deletion.
  • Activity log list views do not expose request/response bodies (only available in detail view).
  • CIO_ReadOnly permission set excludes Request_Body__c and Response_Body__c fields.
  • Error messages returned to the client are generic (no stack traces or internal details).

No third-party data sharing

CIO Pipelines does not share PII with any third party other than Customer.io itself, which is the integration target. We do not:

  • Send analytics events to external services
  • Ship telemetry from subscriber orgs to Creative Round
  • Contact any URL other than the configured Customer.io endpoints
  • Ship usage reports off the customer's Salesforce org

The only outbound HTTP traffic is to:

  • cdp.customer.io or cdp-eu.customer.io (CDP writes)
  • api.customer.io or api-eu.customer.io (App API reads, via Named Credential)

Both endpoints are pre-registered as Remote Site Settings with SSL enforced.

Permission sets

CIO_Admin

  • Full CRUD on CIO_Event_Trigger__c, CIO_Field_Mapping__c, CIO_Activity_Log__c
  • Read/write access to all non-required custom fields
  • Access to CIO_Settings__c custom setting (API credentials)
  • View Encrypted Data (so admins can edit and round-trip API keys)
  • CIO_Home tab visibility

CIO_ReadOnly

  • Read-only access to event triggers, field mappings, and activity log
  • No access to request/response body fields (PII protection)
  • No access to CIO_Settings__c custom setting

Encryption & transport

  • All credentials at rest: Salesforce platform encryption (AES-256) on EncryptedText fields
  • All API traffic in transit: TLS via Salesforce HTTP callouts + Named Credentials
  • Platform encryption applies to the underlying database; backup/restore inherits encryption

Testing

  • 36 test classes cover 40 production Apex classes
  • All tests run in managed-package context (System.runAs(CIO_TestDataFactory.getAdminUser()))
  • HTTP callouts are mocked via CIO_HttpCalloutMock
  • No test uses @isTest(SeeAllData=true)
  • Negative-path tests for the SOQL filter validator, webhook HMAC verification, and FLS enforcement

Reporting a vulnerability

Email security findings to james@creativeround.com. We will respond within 2 business days and coordinate disclosure with affected installations.


Need a SOC 2 questionnaire response or a custom DPA? Available on the Enterprise tier.

Talk to us