Trust Center

Security Controls

Authentication, encryption, network isolation, key management, audit controls, and compliance posture for VaultPDF. For CISO, security teams, and pen-test scoping.

Last updated: 2026-05-31. Version: 1.0.

For architecture context see Architecture & Data Flow.


1. Authentication and Authorisation

API Authentication

EndpointMethodNotes
Dispatcher render/workflow endpointsAzure Function host key (HTTPS)Key stored in SPFx property bag (encrypted at rest by SharePoint); never in source code
Dispatcher admin/audit endpointsAzure AD Bearer JWTauthLevel: "function" plus explicit JWT exp check on every hop
Licensing APILicense key (HTTPS header)Key stored in Azure Key Vault; retrieved via MSI at startup
eSign Portal - Dispatcher token verifyHMAC-SHA256 portal token4-hour TTL; token bound to correlationId, action, and timestamp
SharePoint Graph callsManaged Identity (MSI)Sites.ReadWrite.All granted via Grant-SpAccess.ps1; no passwords or client secrets

Authentication Flow

flowchart LR
    subgraph Callers["External Callers"]
        SPFx["SPFx App<br/>(SharePoint)"]
        AdminTool["Admin / Audit Tool"]
        Approver["Approver Browser"]
        ESignPortal["eSign Portal<br/>(VaultPDF-operated)"]
    end

    subgraph Dispatcher["The Dispatcher - func-dispatcher (your Azure subscription)"]
        RenderAPI["Render / Workflow<br/>Endpoints"]
        AdminAPI["Admin / Audit<br/>Endpoints"]
        TokenVerify["eSign Token<br/>Verify Endpoint"]
    end

    subgraph AzureServices["Azure Services - Managed Identity Only (no passwords)"]
        SPO["SharePoint<br/>Graph API"]
        KV["Azure Key Vault"]
        SB["Azure Service Bus queues"]
    end

    subgraph Processor["The Vault Engine - func-processor (your Azure subscription)"]
        SBTrigger["Service Bus<br/>Trigger (MSI)"]
    end

    SPFx -->|"Function Key · HTTPS"| RenderAPI
    AdminTool -->|"Azure AD Bearer JWT (exp checked every hop)"| AdminAPI
    Approver -->|"HMAC portal token - 4-hour TTL"| TokenVerify
    ESignPortal -->|"HMAC portal token · HTTPS"| TokenVerify

    RenderAPI -->|"MSI"| SPO
    RenderAPI -->|"MSI"| KV
    RenderAPI -->|"MSI"| SB
    SB -->|"MSI trigger"| SBTrigger
    SBTrigger -->|"MSI"| SPO
    SBTrigger -->|"MSI"| KV

Authorisation

  • Feature flags are enforced at render time via license-gated feature gates (licenseFeatures.ts); the NODE_ENV !== 'production' guard prevents override in production deployments.
  • Multi-stage workflow approvals use per-step HMAC-SHA256 approver-email hashing with crypto.timingSafeEqual comparison (prevents timing oracles).
  • Audit-event API requires valid Bearer JWT; tenant scope is enforced on every query.

Licensing Integrity and Enforcement Model

VaultPDF implements a tiered licensing enforcement model to reduce runtime dependency on external systems while maintaining tamper-evident integrity.

Entitlement Verification

  • All license entitlements are cryptographically signed by VaultPDF using JWS ES256 (ECDSA P-256).
  • VaultPDF holds the private signing key. Your Dispatcher Function holds only the public verification key - it can verify but never forge entitlements.
  • The JWS signature is validated before every use in runtime decision-making.
  • Any modification to the cached license.vpdf file causes signature verification to fail; the file is discarded and the tier cascade falls through to Tier 3 (Licensing API).

Runtime Enforcement

  • The Dispatcher evaluates a 4-tier cascade: in-memory cache (24 h TTL) → SharePoint license.vpdf → Licensing API → 48-hour grace (API unavailability only).
  • Feature gating is enforced locally via the cached entitlement state. No external call is required when the in-memory cache (Tier 1) or SharePoint file (Tier 2) is valid.
  • When both local tiers miss, the Dispatcher calls the Licensing API directly (Tier 3); this carries only licenseKey and tenantId - no document content.

Sync Security Controls

  • Licensing sync and Tier 3 runtime calls use HTTPS (TLS 1.2+).
  • Authentication uses a VaultPDF-issued identity token (JWS ES256) bound to your licenseKey and tenantId; no user credentials or document content are transmitted.
  • The signed entitlement payload includes a tenant ID binding (tid claim) verified before the file is written to SharePoint; a tid mismatch causes the response to be rejected.

Resilience and Failure Behaviour

ScenarioOutcome
Licensing API temporarily unreachableSystem operates on Tier 1/2 cache. If both miss, 48-hour grace activates using last known-good entitlement. Independently, the VaultNotification rate-limit cache is fail-open - it keeps serving the last-known limits for up to 24 h and never blocks a send when the API is unreachable. No impact to document generation or notifications.
Grace period expires (API still unreachable)Access denied entirely. System resumes automatically when API is reachable.
License revoked or expired (API responds)Nightly sync deletes license.vpdf; in-memory cache cleared. Next request is denied. Grace period does not apply to genuine revocations or expired licenses.
VaultNotification service temporarily unavailableNotification requests are held on a durable Azure Service Bus queue and processed when the service recovers - emails are delayed, not dropped. Document generation, rendering, and signing are unaffected because notifications are a downstream, asynchronous step.
eSign Portal temporarily unavailableThe portal is a stateless relay; the signing page itself is served from your own Dispatcher function. New signing-link redirects pause until it recovers; already-served signing pages and in-progress signatures are unaffected.

2. Data Encryption

In Transit

  • All HTTP endpoints require HTTPS (TLS 1.2+). The Dispatcher function app has httpsOnly enforced in Bicep.
  • Azure Service Bus queues connections use AMQP over TLS.
  • Internal Azure backbone traffic (Isolated Azure Function - Azure Blob Storage, Azure Key Vault) uses TLS enforced by Azure.

At Rest

DataEncryptionKey location
Azure Blob Storage (outputs, audit, archives)AES-256 (Azure Storage Service Encryption)Microsoft-managed (customer-managed key option available via Azure Key Vault)
Azure Key Vault secretsAES-256Azure HSM-backed
Approver email addresses in workflow stateAES-256-GCM + random IVYour Azure Key Vault (ESIGN_ENCRYPTION_KEY)
Portal tokensHKDF-derived kEnc (AES-GCM) + kMac (HMAC-SHA256)Your Azure Key Vault
.vpdf audit archivesAES-256 (Azure Storage SSE) + HMAC-SHA256 manifestStorage SSE + your AUDIT_REPORT_HMAC_KEY environment variable

3. Network Controls

VaultPDF uses a tiered network model so each deployment matches its environment and compliance needs. In all tiers, storage access is governed by Microsoft Entra ID RBAC (managed-identity only), allowSharedKeyAccess: false (no shared-key or anonymous access), and WORM immutability on the audit container.

Development / Demo deployments

Storage accounts run with defaultAction: Allow, secured by RBAC + no-shared-key + WORM. This avoids VNet provisioning for non-production environments while keeping identity-based access control fully enforced. No document data is exposed: every account still requires a valid managed-identity role to read or write.

Deployed on the Azure Functions Flex Consumption plan with VNet integration. All four storage accounts (stDisp, stProc, stData, stOut) use networkAcls.defaultAction: Deny. Function App access to storage traverses the VNet via subnet service endpoints; external internet access to the data plane is blocked at the network ACL layer. This is the recommended production posture and is enabled by supplying the vnetSubnetId deployment parameter - no plan upgrade required.

Production - Tier 2 (Dedicated / Regulated)

For customers requiring dedicated compute or specific regulatory isolation (e.g. FedRAMP High, air-gapped, or internal policies mandating isolated infrastructure), Tier 2 extends Tier 1 with additional isolation. Tier 2 capabilities are at two different levels of readiness today - stated plainly here rather than bundled as a single offering:

Available today, as a deployment parameter: Service Bus network isolation (serviceBusSku=Premium, default: Standard). Namespace-level IP/VNet firewall rules (and Private Endpoints) for Service Bus are a Premium-tier-only Azure capability - Tier 1's Standard-tier namespace is RBAC-only (managed-identity access, no shared keys) with no network ACL option available at that tier at all; a deployment attempting one on Standard fails outright rather than silently no-op'ing. Premium costs materially more (~$677/month per namespace vs. Standard's ~$10/month) and is deliberately restricted to production deployments - a non-production deployment requesting it is blocked at deploy time - so it is only ever chosen as a deliberate, informed decision made with the customer at onboarding, never a default or an accidental selection.

Planning note: moving an existing customer from Standard to Premium later is a namespace migration requiring a scheduled maintenance window, not a live configuration toggle - Azure provisions a new Premium namespace and migrates entities into it (the DNS name is preserved, so client connection strings are unaffected, but messages in flight at the moment of cutover are not carried over). This is why the tier is decided once, at onboarding, rather than deferred.

Not yet implemented - roadmap, requires an engineering scoping conversation: a dedicated (Elastic Premium) compute plan for the Function Apps and Private Endpoints for storage/Key Vault. These are not currently exposed as deployment parameters. A customer whose compliance requirement depends on either of these should raise it during onboarding scoping, not assume it is available at go-live.

Choosing Standard vs. Premium

Most customers, including most compliance-driven ones, belong on Tier 1 / Standard:

  • Your requirement is that the document data plane (storage) be network-isolated - Tier 1 already delivers this via networkAcls.defaultAction: Deny and VNet service endpoints on all four storage accounts.
  • You don't have a specific citation requiring the messaging/queueing layer itself to be network-restricted, as distinct from the data it carries.
  • Managed-identity RBAC (no shared keys, no connection strings) is an acceptable control for Service Bus on its own - reasonable here because Service Bus carries workflow metadata (job signals, delivery events), not document content or file bytes.
  • Cost efficiency matters: Standard Service Bus is ~$10/month; Premium is ~$677/month per customer namespace, recurring.

Consider Tier 2 / Premium Service Bus when:

  • A named regulatory framework or internal security policy explicitly requires network-level isolation of all backend Azure services - not just the storage data plane. FedRAMP High system boundaries are the common example.
  • Your organization operates under a blanket policy that any Azure resource with a public endpoint is out of bounds regardless of auth model, even one gated by RBAC-only access.
  • You can commit to the decision at onboarding - Premium is not something to add later without a scheduled maintenance window, so "we might need it eventually" should be resolved before go-live, not deferred.

If your requirement extends to dedicated compute or Private Endpoints for storage/Key Vault (beyond Service Bus), flag that separately during onboarding scoping - unlike Service Bus tier, those are not yet a turnkey parameter.

Application endpoints (all tiers)

The Dispatcher's HTTP endpoints are reachable over the public internet by design - they serve SPFx (browser) clients, external signers, and integration callers (Power Platform, the eSign Portal). These endpoints are secured by layered authentication rather than network restriction: Azure Function keys (a second factor on initiator routes), Entra ID JWT bearer enforcement, HMAC-SHA256 signatures on portal callbacks, and opaque signed tokens on signer and delivery routes. The data plane (storage) is network-isolated in Tier 1 and Tier 2 even though the application endpoints remain publicly reachable.

VaultPDF's outbound calls to the Licensing API and eSign Portal use HTTPS/TLS 1.2+. No inbound firewall rules need to be opened for these calls.


4. Key Management

  • All secrets are stored in your Azure Key Vault. VaultPDF vendor staff have no standing access.
  • HKDF root key derives kEnc and kMac per-token via HKDF(root, tokenId, purpose).
  • enablePurgeProtection: true on Azure Key Vault (set by Bicep; irreversible); 90-day soft-delete retention.
  • Key rotation is an operator action via az keyvault secret set. Approver-email ciphertext stores a keyId field to support future re-encryption on key roll.

Key Management Flow

flowchart TD
    KV["🔐 Azure Key Vault<br/>(your subscription)<br/>VaultPDF vendor staff have NO standing access"]

    KV -->|"HKDF root key (retrieved via MSI)"| HKDF

    subgraph HKDF["HKDF Derivation - per token"]
        direction LR
        kEnc["kEnc<br/>AES-GCM encrypt<br/>portal token payload"]
        kMac["kMac<br/>HMAC-SHA256 sign<br/>portal token"]
    end

    KV -->|"Approver-email AES-256-GCM key (retrieved via MSI)"| AES["AES-256-GCM<br/>Encrypt approver PII<br/>in Azure Table Storage"]
    KV -->|"ACS email key (optional) - BYO email only"| ACS["Azure Communication Services<br/>BYO outbound email"]

    AppSettings["Azure App Settings<br/>(your Function App config)"] -->|"AUDIT_REPORT_HMAC_KEY"| HMACSign["HMAC-SHA256<br/>Sign verification report PDFs<br/>+ upload .sig.json companion"]

    style KV fill:#e8f5e9,stroke:#388e3c

5. Audit and Tamper-Resistance

ControlStatus
Append-only audit JSONL blobEach operation appends; no overwrites
Sequential event ordering (hash chain)Each event includes previousHash; verifier API checks chain integrity
HMAC-signed verification reportsAUDIT_REPORT_HMAC_KEY signs each verify-report PDF; companion .sig.json uploaded
Immutable storage containersDeploy with -LockImmutability flag (irreversible; enables WORM for audit containers)
Storage geo-redundancyStandard_GRS for audit and output storage (Bicep default)
Azure Key Vault purge protectionenablePurgeProtection: true; 90-day retention
Signed audit tip (daily)Planned - daily signed tip for long-gap tamper detection

6. Input Validation and Injection Prevention

Attack vectorControl
OData injection (licensing queries)odata tagged-template literal; single-quote doubling; no raw string concatenation
SSRF (external asset fetch)DNS resolution mandatory; resolved IP validated against RFC1918 blocklist; IP pinned for duration of fetch
ZIP slip (.vpdf extraction)assertSafeArchiveEntryName rejects traversal, absolute, UNC, drive, and control-char paths before any extraction
Condition engine code injectionZero eval/Function usage; BLOCKED_PROTOTYPE_KEYS guard; MAX_EXPRESSION_LENGTH 4096; MAX_TOKEN_COUNT 1024; MAX_EVAL_DEPTH 200; 19 security tests in CI
Duplicate seal (replay)Service Bus messageId = {correlationId}-workflow-seal; requiresDuplicateDetection: true on queue
Concurrent approval raceOptimistic concurrency: If-Match ETag on all 4 intermediate updateWorkflowState calls; 412 - HTTP 409 to caller
Schema substitution mid-workflowloadSchema verifies SHA-256 of fetched YAML against schemaSha256 stored at workflow start; throws on mismatch

7. Dependency and Supply Chain

  • pnpm lockfile with exact version pinning; CI validates lockfile integrity.
  • SBOM generation via CycloneDX from pnpm lockfile - integration in progress.
  • No eval and no dynamic require() in production code paths.
  • ZIP-slip path validation enforced in archive extraction; third-party dependencies tracked via Dependabot.

8. Rate Limiting and Abuse Prevention

  • Licensing API rate limiter uses Azure Table Storage and ETag optimistic concurrency; scale-safe across multiple Isolated Azure Function instances.
  • SPFx command set has per-item in-flight debounce (_inFlight = new Set<string>()); duplicate clicks are dropped.
  • Dashboard polling uses a 60-second base interval with adaptive backoff on 429 (doubles up to 8x, maximum approximately 8 minutes).

9. Compliance Posture

StandardStatus
GDPR (EU)Data stays in customer's Azure region; DPA available on request; sub-processor list in Sub-Processor List
HIPAA / HITECHCustomer-owned infrastructure model supports BAA with Microsoft; no PHI transits VaultPDF systems
FedRAMP ModerateCustomer-owned deployment into Azure Government regions supported; controls mapping available on request
SOC 2 Type IPlanned - engage external auditor
ISO 27001Planned - leverage SOC 2 control mapping
PDF/UA-1 (Section 508)Structural tagging, MarkInfo, StructTreeRoot, Lang, ViewerPreferences/DisplayDocTitle implemented
WCAG 2.1 AAPDF-side implemented; UI accessibility improvements tracked in audit backlog

Pen-Test Scoping and Security Questionnaires

Contact our security team for pen-test scoping, architecture review, and compliance mapping.

On this page