Security & Verification

Security & Verification

How REFRACT Platform enforces security at every layer - from Entra ID authentication and Managed Identity through item-level access control, document integrity verification, and deep-link safety in REFRACT Lifecycle.

This page explains how REFRACT Platform security works in practice - the specific mechanisms, enforcement order, and what is checked at each boundary. For compliance posture, sub-processor lists, and pen-test scoping, see the Trust Center.


Data Residency

REFRACT PDF rendering happens inside your own Azure subscription. The rendering engine runs in your Dispatcher Function App. Templates are retrieved from your SharePoint. Generated PDFs are stored in your SharePoint or your Azure Blob Storage.

The REFRACT eSign, Delivery, and Workflow products additionally involve a REFRACT-hosted portal, which redirects every document download to your own deployment rather than relaying the bytes itself, and a shared notification service - see What Crosses to REFRACT Shared Services below for exactly what each product sends.

Tenant-Native Rendering

The PDF engine runs inside your Azure Function App. Document data is processed in-memory within your subscription and never sent to REFRACT PDF servers for rendering.

Customer-Controlled Storage

All outputs, templates, audit logs, and workflow state are stored in storage you control - SharePoint or Azure Blob Storage - using Managed Identity access only.

Vendor Access Limited to Licensing and Notifications

Licensing sends your tenant identifier, license key, identity token, and deployment address. Usage reporting sends counts. The shared notification service sends invitation and one-time-code emails on your behalf. Neither includes document content.


Security Architecture Overview

flowchart TB
  subgraph External["Entry Points"]
    SPFx["SharePoint / SPFx<br/>REFRACT Lifecycle UI"]
    D365["Dynamics 365 / Power Automate<br/>Power Platform Connector"]
    Portal["REFRACT eSign Portal<br/>(External Signers)"]
  end

  subgraph CustomerTenant["Your Azure Environment"]
    Entra["Microsoft Entra ID<br/>Authentication & JWT Issuance"]
    Disp["REFRACT Dispatcher Function App<br/>JWT validation · Feature gates · Render engine"]
    SB["Azure Service Bus<br/>Priority Queues (MSI-connected)"]
    Proc["Processor Function Apps<br/>REFRACT Workflow · REFRACT eSign · REFRACT Delivery · REFRACT Audit"]
    KV["Azure Key Vault<br/>All secrets"]
    SP["SharePoint<br/>Templates · Generated Docs · Activity List"]
    Blob["Azure Blob Storage<br/>Audit JSONL · Dispatch payloads · Archives"]
    Entra --> Disp
    Disp --> SB
    Disp --> KV
    Disp --> SP
    Disp --> Blob
    SB --> Proc
    Proc --> KV
    Proc --> SP
    Proc --> Blob
  end

  subgraph VaultShared["REFRACT Platform Shared Services"]
    Lic["Licensing API<br/>licenseKey + tenantId only"]
    Notify["REFRACT Notification<br/>Metadata only - no document content"]
  end

  SPFx -->|"Entra ID Bearer JWT"| Disp
  D365 -->|"OAuth 2.0 Bearer JWT"| Disp
  Portal -.->|"HMAC portal token · HTTPS"| Disp
  Disp -.->|"licenseKey + tenantId"| Lic
  Proc -.->|"Event metadata only"| Notify

What Crosses to REFRACT Shared Services

This reference answers the question that matters most for data residency and compliance reviews: exactly which data transits REFRACT Shared Services infrastructure, per product.

Two things still pass through the hosted portal, in memory only

Document bytes never transit the REFRACT-hosted portal for a download, across REFRACT eSign, Delivery, and Workflow alike: the portal redirects the browser to your own Dispatcher or SharePoint site, which serves the bytes directly. Two narrower exceptions remain, both in memory only and never written to the portal's own storage: when an eSign signer submits their signature, the signature image and field values pass through the portal on their way to your Dispatcher; and when a REFRACT Workflow participant uploads an attachment, the file passes through the portal on its way to your Dispatcher. Licensing and notifications are separate, metadata-scoped exchanges described below.

Data transit reference by product

DataYour subscription onlyTransits the REFRACT-hosted portalDetail
All products
Document source data, payloads, templatesYesNeverRendering runs in your Dispatcher
Generated PDF bytes at restYesNeverStored in your Blob Storage or SharePoint
License validation and usage reporting-Yes - Licensing APITenant identifier, license key, identity token, deployment address; usage reporting, only when it is configured (the standard templates do not configure it), sends counts only. No document content.
REFRACT eSign
Document the signer viewsYesNeverServed via your Dispatcher; the portal redirects the signer to your deployment for the document, signed copy, certificate, and download
Signer invitation email + OTP code-Yes - via the portal's own notification sendingPortal sends these directly; not routed through your notification queue
Signature PNG and manifest field values (drawn/entered in browser)Yes - stored at restTransits in-memoryThe portal posts an HMAC-signed callback containing these values to your Dispatcher; the portal does not persist them to its own storage
Evidence certificateYesNeverGenerated in your Processor; stored in your Blob
REFRACT Delivery / REFRACT Workflow
Document bytes the recipient/participant accessesYesNeverREFRACT Workflow: served via your Dispatcher, the same pattern REFRACT eSign uses. REFRACT Delivery: served via your Dispatcher, or, when the document is SharePoint-stored, redirected to your SharePoint site directly. The portal never receives the bytes either way.
Workflow attachment downloadsYesNeverSame redirect pattern as document downloads above
Workflow attachment uploadsYesTransits in-memoryUploaded through the portal's own process to your Dispatcher, in memory only, never written to the portal's storage; your Dispatcher writes the bytes to your Blob Storage
Recipient/participant invitation email + portal link-Yes - notification metadata (vault-shared mode)Email address, name, document name, message body, any one-time code; no document content
Session/workflow state, decisions, approvalsYesNeverStored in your Table Storage + audit log
Notifications (vault-shared mode)
Email address, portal link, document name, message body, one-time codes-YesCovered under the Refract Logic DPA. Use customer-acs mode to send it from your own tenant instead, for Delivery, Workflow, and eSign. REFRACT eSign emails are still composed by the REFRACT-hosted eSign Portal.
Document bytes, file content, form field valuesNeverNeverNot included in any notification under any mode

Notes on in-memory transit and byte paths

Signature and field data (REFRACT eSign): The signer completes fields and draws their signature in the browser on the portal UI. When they submit, the portal constructs an HMAC-signed callback body - which includes the field values and the signature PNG - and POSTs it to your Dispatcher. This data transits the portal in-memory during that callback; it is not written to the portal's own storage, and the callback is HMAC-verified by your Dispatcher before use.

File attachments (REFRACT Workflow): Attachment uploads go through the portal's own process to POST /api/workflow/{workflowId}/attachment on your Dispatcher, in memory only, which receives the raw bytes directly and writes them to your Blob Storage - not a pre-signed direct-to-blob upload. A 25 MB size cap and a content-type allowlist are enforced. Attachment downloads are the opposite of uploads here: the portal redirects the browser to your Dispatcher rather than proxying the bytes - see "Document access" below.

Document access (REFRACT eSign, Delivery, and Workflow): For all three products, every document and attachment download follows the same pattern: the portal resolves a per-download credential (JSON only, no bytes) and redirects the browser to your own deployment, which serves the bytes directly. For REFRACT eSign and REFRACT Workflow, that deployment is always your Dispatcher, streaming from your Blob Storage. For REFRACT Delivery, it is your Dispatcher when the document is Blob-stored, or your SharePoint site directly when it is SharePoint-stored. The portal's process is in the request path but never in the byte path for a download. This is a change from an earlier design, where Delivery and Workflow downloads were relayed through the portal's own process rather than redirected; both now match REFRACT eSign's redirect-only pattern.

Notification emails: In vault-shared mode (the default), the notification payload - recipient email, portal link, document name, message body, and any one-time code - transits the REFRACT notification service. For a REFRACT Dispatch batch invitation, the service also holds the email's result (identifiers, a keyed hash of the recipient, sent or failed, stage, and error code, with no address) until your Processor collects it, for at most 30 days. In customer-acs mode, Delivery, Workflow, and eSign notifications are sent from your own Azure Communication Services instance instead. REFRACT eSign emails are still composed by the REFRACT-hosted eSign Portal, which hands each one to your Dispatcher - see REFRACT eSign emails.


Layer 1 - Microsoft Entra ID Authentication

Every request to REFRACT Platform begins at Entra ID. This is not optional and cannot be bypassed.

SharePoint / SPFx callers

REFRACT Lifecycle is a SharePoint Framework (SPFx) web part and command set deployed inside your SharePoint environment. Before the SPFx components load:

  1. The user must authenticate to your SharePoint site with a valid Entra ID session.
  2. SharePoint enforces site-level permissions. A user without access to the REFRACT PDF SharePoint site cannot reach the page.
  3. Only after a valid SharePoint session is established does the SPFx runtime load and the REFRACT Lifecycle workspace become visible.

There is no way to access REFRACT Lifecycle content by guessing or crafting a URL. Authentication to SharePoint is a hard prerequisite.

Power Platform / Dynamics 365 callers

The REFRACT Platform Power Platform Connector uses OAuth 2.0 with Entra ID as the identity provider. Every API call carries a Bearer JWT. The Dispatcher Function validates the token on every request - there is no session or cookie that persists across calls.

Direct API callers

Direct calls to the Dispatcher Function API require a valid Microsoft Entra ID Bearer JWT, validated on every request against the aud, iss, tid, and exp claims. There is no Azure Functions host key (?code=) on any Dispatcher route - every route is registered anonymous at the platform level and relies entirely on this JWT validation. After it, a signed-in user's token must carry the user_impersonation scope (403 SCOPE_MISSING otherwise), and an app-only token must hold the Render.Access application permission (403 ROLE_MISSING otherwise). An app-only token can never approve, reject, escalate, or decide a batch (403 APP_CANNOT_DECIDE). See Authentication.


Layer 2 - REFRACT Lifecycle Access Control

REFRACT Lifecycle enforces a four-layer access control model. All four layers apply identically whether the workspace is opened manually (by clicking the command button) or via a deep link.

Layer 2a - SharePoint site authentication

Covered above. Unauthenticated users cannot reach the page.

Layer 2b - SharePoint list permissions (server-enforced)

All data in REFRACT Lifecycle is read from the REFRACT_Activity SharePoint list via SharePoint REST API. SharePoint enforces list-level read permissions server-side on every request. A user who does not have Read access to the REFRACT_Activity list receives an HTTP 403 - the SPFx client receives no data regardless of what filters are set.

This is independent of the SPFx UI. The UI cannot show data that SharePoint refuses to return.

Layer 2c - Admin role resolution (live server-side call on every open)

When the REFRACT Lifecycle workspace opens, it immediately makes two live SharePoint REST calls before displaying any results:

GET /_api/web/currentuser?$select=IsSiteAdmin
GET /_api/web/currentuser/groups?$select=Title

These calls resolve the user's actual admin status from the server at open time. The isAdmin value derived from these calls controls:

  • Whether the user sees all items or only items they are permitted to see
  • Whether the Configuration panel and admin-only actions are available

There is no client-side override for admin status. A URL parameter, a manipulated prop, or a cached value cannot elevate a user's permissions - the live server response is authoritative.

A user is treated as admin if either:

  • They are a SharePoint Site Collection Administrator, or
  • They are a member of the REFRACT.Admin SharePoint group

Layer 2d - Item-level access control (VPDFRestrictionMap)

After SharePoint returns the list of activity items, each item passes through a client-side visibility check before being shown. Items where VPDFExcludeFromSearch=true never return from SharePoint at all (pre-filtered at the OData query level). For all other items, the following rules apply:

ConditionResult
User is REFRACT PDF AdminItem visible at admin level (full metadata)
Item has no VPDFRestrictionMapItem visible at operational level (open access)
User's email matches VPDFInitiatedBy or VPDFSignerEmailItem visible at operational level (creator/participant)
User's SharePoint group matches a VPDFRestrictionMap entryVisible at the level granted in that entry
No matchItem silently excluded from results

VPDFRestrictionMap is a pipe-delimited string stored on each activity item. An example value:

Finance.Approvers=admin|HR.Managers=operational

This means members of the Finance.Approvers SP group see the item at admin level; members of HR.Managers see it at operational level; everyone else sees nothing.

When an item is visible but at operational level (not admin), sensitive fields such as PdfHash, internal metadata, and document integrity controls are redacted - the item is still findable and openable, but privileged information is withheld.

Restriction Map Precedence

If a user matches multiple group entries in VPDFRestrictionMap, they receive the highest matching visibility level. Creator/participant status (operational) is checked before group membership and serves as a shortcut - no group lookup is required for the item's own initiator or signers.


Layer 3 - API Authentication (Dispatcher Function)

Calls from REFRACT Lifecycle to the Dispatcher Function for extended data (audit events, signing state, delivery state, workflow state) use AadHttpClient - the SharePoint Framework's AAD-integrated HTTP client.

The SPFx package asks for the REFRACT Dispatcher API / user_impersonation permission, and deploying the package does not grant it. An administrator approves the request in the SharePoint admin center -> Advanced -> API access, which grants the delegated permission to SharePoint's "SharePoint Online Client Extensibility Web Application Principal". Until it is approved, REFRACT Lifecycle cannot call the Dispatcher.

Every such request automatically attaches a Bearer JWT for the "REFRACT Dispatcher API" app registration (REFRACT Lifecycle reads that app's ID from the Dispatcher's /api/audience-config route), validated by the Dispatcher on receipt against the aud, iss, tid, and exp claims. There is no function key on any of these routes. The token is not readable from the browser's URL bar, local storage, or network responses in plaintext. It is issued by Entra ID with a short TTL and is automatically refreshed by the SPFx AAD client.

Reading the records REFRACT holds about a document (audit timeline events, signing and delivery status with participant addresses, workflow data and exports, opening a workflow for review, files stored in your Blob Storage and opened through the Dispatcher, evidence chain exports and archives, Section 508 outputs, the integrity verdict, starting and reading verification and reproduction, explain traces and PDFs, and batch records), re-rendering a stored payload as a signed-in user, or sending a stored document as a signed-in user (Send for Signature, OTC Signature, Send for Delivery), also requires the Lifecycle.Reader app role on the "REFRACT Dispatcher API" app, carried in the token's roles claim. A caller without it receives 403 with code ROLE_MISSING. This check is separate from the SharePoint layers above: SharePoint decides which documents a person can find, and the role decides whether the Dispatcher returns REFRACT's records about them. See Access: the Lifecycle.Reader Role for what it covers, and Give people access to document records for how to assign it to people.


Layer 4 - Managed Identity for Azure Services

Inside the Dispatcher and Processor Function Apps, access to Azure services uses Managed Identity (MSI). No passwords, connection strings with credentials, or client secrets are stored in application code or environment variables for Azure resource access. SharePoint is the exception: both Function Apps reach it through Microsoft Graph as the REFRACT SharePoint Access app registration you create, whose client secret is stored in your Key Vault as sp-secrets and referenced from the SP_SECRETS setting. They use the managed identity for SharePoint only when sp-secrets holds no client ID and secret.

ResourceAccess method
SharePoint (templates, activity list, generated docs)REFRACT SharePoint Access via Microsoft Graph - Sites.ReadWrite.All; client secret held in Azure Key Vault (sp-secrets)
Microsoft Entra group membership (access checks)MSI via Microsoft Graph - GroupMember.Read.All
Azure Blob Storage (payloads, archives, audit JSONL)MSI - Storage Blob Data Contributor
Azure Service Bus (dispatch queues)MSI - Azure Service Bus Data Sender/Receiver
Azure Table Storage (batch dispatch state)MSI - Storage Table Data Contributor
Azure Key Vault (all secrets)MSI - Key Vault Secrets User

The deployment template grants Refract Logic no access to your Key Vault, and grants the account that runs the deployment no role. When deploy.ps1 has a missing secret to write, it grants the signed-in account Key Vault Secrets Officer on the vault for that run only, and removes the assignment when the run ends, including when the run fails. It removes only an assignment it created: one that already existed (granted by hand, inherited from the resource group or subscription, or made permanently by an earlier version of the template) is left in place, and deploy.ps1 -Preview lists it with the command to remove it. If someone outside your organisation ran an earlier version of deploy.ps1 for you, check for that standing assignment and remove it. The secrets your deployment uses (JWT signing keys, encryption keys, ACS keys) are read by your Function Apps' managed identities (Key Vault Secrets User) and are also accessible to anyone holding a role on the vault.


Licensing Security

License entitlements are cryptographically signed using JWS ES256 (ECDSA P-256). REFRACT PDF holds the private signing key. Your Dispatcher holds only the public verification key - it can verify entitlements but cannot forge them.

The runtime uses a 4-tier cascade:

Tier 1 - In-memory cache (24-hour TTL)

The verified entitlement is held in memory. No external call. Tier 2+ is only reached on cache miss or startup.

Tier 2 - SharePoint license.json

The Dispatcher reads the signed entitlement file from your SharePoint. Any modification to this file causes JWS signature verification to fail - the file is discarded and Tier 3 is attempted.

Tier 3 - Licensing API

A direct HTTPS call to POST /v1/validate at license.refractplatform.com, carrying tenantId, licenseKey, an identity token, and your deployment address. The response is an ES256 JWS-signed entitlement, not encrypted, and includes a tenant ID binding. If the tid claim in the response does not match your configured tenant, the response is rejected.

Tier 4 - 48-hour grace period

If the Licensing API is unreachable (outage, network issue), the Dispatcher operates on the last known-good entitlement for up to 48 hours. Grace does not apply to genuine license revocations or expirations - those are communicated in the Tier 3 response and take effect immediately.


REFRACT Lifecycle supports deep links - URLs with query parameters such as ?batchId=, ?correlationId=, or ?sourceSystem= that pre-populate the search and auto-open the workspace. This is useful for source systems (Dynamics 365, Business Central) that want to provide a one-click link directly to a specific document's lifecycle view.

Deep links do not bypass any security layer

A deep link pre-populates filter state. It does not modify authentication, admin resolution, SP list permissions, or item-level visibility checks. Every layer described above runs identically whether the workspace opens via button click or deep link.

URLEffect
Home.aspx?correlationId=d8cb1510-8290-40f8-8592-702eaa9838a6Workspace opens with CorrelationId pre-populated in search
Home.aspx?batchId=082ab853-7852-47f0-b078-1927d2d92619Workspace opens with BatchId pre-populated in search
Home.aspx?sourceSystem=D365_FOWorkspace opens with Source System filter set to D365_FO
Home.aspx?q=INV-001&sourceSystem=D365_FOWorkspace opens with text search and source system filter combined
  • Grant access to a user who is not authenticated to SharePoint
  • Elevate a user's admin status
  • Show items the user's SP permissions do not allow
  • Show items the user's VPDFRestrictionMap visibility does not permit

A non-privileged user who follows a deep link with a valid ?correlationId=... will see zero results if the corresponding activity item is restricted - the search executes, returns nothing (because SP enforces permissions and the visibility check excludes the item), and the workspace is empty.

CorrelationId and BatchId are globally unique

CorrelationIds and BatchIds are UUID v4 values generated by REFRACT Platform at render/dispatch time. They are globally unique by construction - no sourceSystem qualifier is needed to identify a specific record. A source system can safely use:

https://your-sharepoint-site/SitePages/Home.aspx?batchId=082ab853-7852-47f0-b078-1927d2d92619

and it will always resolve to exactly that batch. Adding &sourceSystem=D365_FO is harmless but redundant for GUID-based lookups.

IDs are visible in browser history

CorrelationIds and BatchIds in deep-link URLs appear in the browser's address bar, browser history, and corporate proxy logs. These are internal job identifiers, not credentials - they grant no access on their own. However, if your organization's policy restricts internal identifiers in URLs, consider opening REFRACT Lifecycle from an authenticated portal rather than sharing deep links externally.


eSign and Workflow Security

REFRACT eSign signing links are bare session and group identifiers in the URL (/sign?t={sessionId}&g={groupId}), validated against the session record in the portal's own store - they are not HKDF-derived tokens. Because the link carries no credential, holding it verifies nothing: every browser must pass a one-time code sent to the signer's address before it can see or sign the document, and only the most recently verified device can sign. See OTP Verification. A resent eSign invitation carries the same link; eSign links are ended only by the request finishing, expiring, or being revoked. The portal keeps encrypted signer contact details, OTP hashes, and session state in its own database; it is not stateless, though it does not write document bytes, field values, or the signature PNG to that storage - those pass through it in memory on their way to your Dispatcher.

REFRACT Workflow uses a different mechanism: an HMAC-signed portal token, reissued on each valid access, with a 4-hour TTL. The invite link in the email lives at most 1 day. A session started from it ends at the earliest of four hours after the last request, twelve hours after the one-time code was verified (on a workflow that requires it), and four hours after the link itself expires, never later than two days after the link was sent. See When a Session Ends. A newer link replaces older ones. Each participant has one current link: when the sender resends or corrects an invitation, re-asks an approver, or an automatic reminder or escalation is sent, the participant's earlier links stop working once the new email has been accepted for sending. When a participant requests a new link themselves, their earlier link keeps working until the new one is first opened. An older link shows "A newer link was sent to you for this request. Please open the most recent email, or ask for a new link." A download that had already started (its download token lives 2 minutes) still completes.

Approver email addresses in workflow state are encrypted with AES-256-GCM before storage; the key is in your Azure Key Vault. See Input Validation and Injection Prevention below for duplicate-seal replay protection.


Document Integrity Verification

Every PDF generated by REFRACT Platform is SHA-256 hashed at render time. The hash is stored in the REFRACT_Activity list (PdfHash column) and in the audit JSONL.

Verification process

From REFRACT Lifecycle, any document with a stored hash can be verified in one click:

Re-download the PDF

The Dispatcher retrieves the current file from storage (SharePoint or Azure Blob).

Compute current hash

SHA-256 is computed on the downloaded bytes client-side.

Compare against stored hash

The computed hash is compared against the PdfHash value stored at render time in the activity list.

Result

Match = the PDF has not been modified since generation. Mismatch = the file was altered or replaced after the original render. The result is shown in the Integrity panel.

Audit chain integrity

The eSign and Workflow audit chains are HMAC-based: each event's _chain object includes a prevHash field linking it to the prior event's own hash. The verifier API checks chain continuity from the first event to the most recent. A gap or modification in any event breaks the chain from that point forward and is reported. A compromised dispatcher or processor identity - which holds both the storage write access and the Key Vault access needed to re-sign - could rewrite the chain; the guarantee is against a storage-only compromise, not a fully compromised runtime.


Data Encryption

In transit

All communication within REFRACT Platform uses HTTPS with TLS 1.2+. This includes:

  • SPFx → Dispatcher Function
  • Dispatcher → SharePoint Graph API
  • Dispatcher → Azure Blob Storage
  • Dispatcher → Azure Key Vault
  • Dispatcher → Licensing API
  • Azure Service Bus connections (AMQP over TLS)

The Dispatcher Function App has httpsOnly: true enforced in the Bicep deployment template. HTTP is rejected at the Azure layer.

At rest

DataEncryptionKey ownership
Azure Blob Storage (outputs, audit, archives)AES-256 (Azure Storage Service Encryption)Microsoft-managed by default; customer-managed key (CMK) via Azure Key Vault available
Azure Key Vault secretsAES-256 (standard Key Vault SKU, not HSM-backed)Azure - your tenant
Approver email addresses (workflow state)AES-256-GCM + random IVYour Azure Key Vault (ESIGN_ENCRYPTION_KEY)
Portal tokensHKDF-derived AES-GCM + HMAC-SHA256Your Azure Key Vault
Audit verification reportsAES-256 (Storage SSE) + HMAC-SHA256 companion .sig.jsonStorage SSE + your AUDIT_REPORT_HMAC_KEY
Batch dispatch payloadsAES-256 (Azure Storage SSE)Microsoft-managed (see blob note above)

Key Management

All REFRACT Platform secrets are stored in your Azure Key Vault. The deployment Bicep template provisions the Key Vault with:

  • enablePurgeProtection: true - irreversible; prevents secret deletion bypassing soft-delete
  • 30-day soft-delete retention
  • No access granted to Refract Logic. The account that runs the deployment holds Key Vault Secrets Officer only while deploy.ps1 writes a missing secret, and the script removes that assignment at the end of the run

Key rotation is an operator action:

az keyvault secret set \
  --vault-name <your-kv-name> \
  --name esign-encryption-key \
  --value <new-key>

The approver-email ciphertext schema includes a keyId field to support re-encryption on key roll without data loss.

Never store secrets in source code or environment variables

All secrets should be stored in Azure Key Vault and referenced via Key Vault references in your Function App configuration (e.g. @Microsoft.KeyVault(VaultName=kv-name;SecretName=secret-name)). Direct environment variable values for secrets are not recommended for production deployments.


Input Validation and Injection Prevention

Attack vectorControl
OData injection in SharePoint queriesSingle-quote doubling on all user-supplied values; no raw string concatenation in filter expressions
SSRF via external asset fetchDNS resolution mandatory; resolved IP validated against RFC 1918 blocklist; IP pinned for duration of fetch
ZIP slip in .raudit archive extractionassertSafeArchiveEntryName rejects path traversal, absolute paths, UNC paths, drive letters, and control characters before any extraction
Expression injection (conditional styles)Zero eval / Function usage; prototype key blocklist; max expression length 4096; max token count 1024; max eval depth 200
Duplicate seal replayService Bus messageId = {correlationId}-workflow-seal; requiresDuplicateDetection: true on queue
Concurrent approval raceOptimistic ETag concurrency on all intermediate workflow state updates; 412 returned as HTTP 409
Schema substitution mid-workflowSHA-256 of fetched YAML verified against value stored at workflow start; mismatch throws

Security Layer Summary

The following table summarises what is enforced at each boundary for a typical REFRACT Lifecycle open - manual button click or deep link:

LayerEnforced byClient override possible?
Page accessSharePoint / Entra ID authenticationNo - redirect to login if unauthenticated
List data accessSharePoint REST API (server-side)No - 403 if no list permissions
Admin statusLive SP REST calls at open timeNo - server response is authoritative
Item visibilityVPDFRestrictionMap + VPDFExcludeFromSearchNo - filtered at SP query level and post-receive
API calls (audit, signing, delivery)Entra ID Bearer JWT (no function key)No - token issued by Entra ID and validated by the Dispatcher
Caller permissionuser_impersonation scope (people) or Render.Access application permission (apps)No - granted in Microsoft Entra ID
Document records held by REFRACTLifecycle.Reader app role in the token's roles claimNo - roles are assigned in Microsoft Entra ID
Azure resource accessManaged Identity (MSI)No - no credentials accessible to application code
Secret accessAzure Key Vault (MSI)No - Refract Logic is granted no access; the account that runs the deployment holds Secrets Officer only for the run that writes a missing secret
Document integritySHA-256 hash stored at render timeNot applicable - verification is on-demand
LicensingJWS ES256 signed entitlementsNo - signature verified locally; cannot be forged

Certifications

Refract Logic holds no independent certifications today - no SOC 2, no ISO 27001, no HIPAA BAA, and no FedRAMP authorization. Document rendering runs in your own Azure subscription and region, and technical mechanisms like PDF/UA structural tagging (MarkInfo, StructTreeRoot, Lang, ViewerPreferences/DisplayDocTitle) are implemented, but compliance outcomes depend on your own tenant configuration, policies, and legal review.

For the full sub-processor list and data processing addendum, see the Trust Center.


Security Questionnaires and Pen-Test Scoping

Contact the REFRACT Platform security team for security questionnaire responses, architecture review packages, and pen-test scoping documentation.

On this page