Security & Privacy — RGA for HubSpot
For the CISO, CIO, and security team evaluating Revenue Growth Agent (RGA) for use with HubSpot. This page is the HubSpot-specific deep dive. For the platform-wide controls, retention, residency, and sub-processor list, see the Trust & Security Center. The Salesforce companion is Security & Privacy (Salesforce); both integrations share one credential-protection architecture.
RGA's two CRM integrations are built on the same credential-protection model: AES-256-GCM field-level encryption with key separation, per-tenant isolation enforced on every request, and credentials that are write-only at the API boundary. This page describes how that model applies to HubSpot specifically.
Security principles
- Tokens stay protected. HubSpot OAuth access and refresh tokens are encrypted at rest with AES-256-GCM before they touch the database. RGA staff cannot read a stored token from the database alone.
- Defense in depth via key separation. The ciphertext lives in RGA's database (Airtable); the master key lives in RGA's serverless platform environment (a separate system). Compromising either one alone yields nothing usable.
- Ownership verified before storage. RGA does not trust an inbound OAuth callback. It exchanges the authorization code for a token, asks HubSpot which portal that token belongs to, and binds the connection to that HubSpot-reported
hub_id— never to a client-supplied value. - Least privilege and tenant isolation. Every request is authenticated and scoped to the caller's organization. One customer's token cannot read or mutate another customer's HubSpot data.
- No training on your data. HubSpot data is processed to generate prep, discovery, and proposal outputs. It is never used to train AI models.
How RGA connects to HubSpot
RGA is a HubSpot Public App (OAuth, multi-customer distribution) built on HubSpot's Platform 2026.03 project framework. A customer installs it from HubSpot and grants a least-privilege set of scopes.
Install + authorization (OAuth)
- An admin starts the connect flow from the RGA web app (Settings → Integrations → HubSpot) or installs from the HubSpot Marketplace.
- RGA redirects to HubSpot's authorization screen with a signed state parameter. The state is HMAC-SHA256-signed with a server-side secret and carries a 10-minute freshness window. On return, RGA verifies the signature before trusting any value in it — this closes the CSRF surface where a forged callback could bind an attacker's portal to a victim's RGA org.
- After consent, HubSpot redirects to RGA's callback. RGA exchanges the code for tokens, then calls HubSpot's token-introspection endpoint to learn the authoritative
hub_id, and binds the connection to that verified value.
Least-privilege scopes
RGA requests only what the integration uses today:
- Required:
oauth,crm.objects.contacts.read,crm.objects.contacts.write - Optional:
crm.objects.companies.read,crm.objects.leads.read(read-only, used to resolve a lead to its associated contact; granted only on portals whose subscription includes the leads feature)
Deal and timeline scopes are intentionally not requested until deal-level features ship. Scope grants are reviewable in the app listing and at install time.
Token protection
Encrypted at rest with authenticated encryption
HubSpot access and refresh tokens are encrypted with AES-256-GCM (authenticated encryption, NIST SP 800-38D) before they are written to RGA's database — the same cipher and master key that protect Salesforce credentials.
| Property | Value | Why it matters |
|---|---|---|
| Algorithm | AES-256-GCM (NIST SP 800-38D) | Confidentiality and integrity |
| Key length | 256 bits | Brute force is infeasible |
| Initialization vector | 96 bits, random per encryption | Same plaintext never yields the same ciphertext |
| Authentication tag | 128 bits, verified on decrypt | Any tampering fails decryption |
| Format | Versioned (v1:<iv>:<ct>:<tag>) |
Future algorithm migration without breakage |
Key separation across two trust boundaries
This is the control that matters most — identical to the Salesforce model.
| Component | Where it lives | What you'd get by compromising it alone |
|---|---|---|
| Encrypted tokens (ciphertext) | RGA's database (Airtable) | Opaque ciphertext. Useless. |
| Master encryption key | RGA's serverless platform environment (separate system) | A key with no data to decrypt |
An attacker would have to compromise both systems to recover a single plaintext token.
Write-only and per-tenant
- There is no API path that returns a stored token in plaintext — not to RGA staff, not to the admin who connected it. The admin status screen shows only non-secret metadata (hub domain, scopes, connected date).
- Tokens are scoped to the connection the customer authorized, keyed by the verified
hub_id. A short-lived access token is cached per-portal with a refresh safety margin; the cache is invalidated immediately on reconnect or disconnect. - The integration auto-refreshes the access token from the (encrypted) refresh token; rotated refresh tokens are re-encrypted on each refresh.
How the in-CRM card talks to RGA — signed requests, no client-side tokens
HubSpot UI Extensions cannot hold OAuth tokens client-side, and that is by design. The in-CRM Meeting Prepper card calls RGA's backend through hubspot.fetch, HubSpot's documented pattern for marketplace apps, and HubSpot cryptographically signs every request:
- Each request carries an
X-HubSpot-Signature-v3header: an HMAC-SHA256 over the method, the full URL, the exact request body, and a timestamp, keyed with the app's client secret that only HubSpot and RGA hold. - HubSpot appends the portal identity (
portalId) and the acting user inside the signed URL, so a verified signature is simultaneously proof of origin and proof of tenant. A caller cannot forge a request for another customer's portal without the client secret. - RGA's backend verifies the signature with a constant-time comparison, rejects stale timestamps (replay protection), and only then resolves the per-tenant OAuth token by the signed
hub_id, server-side.
This means:
- OAuth tokens never reach the browser. They stay in RGA's backend, encrypted at rest, fetched per request for the verified tenant only.
- The tenant identity RGA acts on comes from HubSpot's signature, not from anything the browser could supply.
- The target URLs the card may call are allowlisted in the app's reviewed configuration.
It is the HubSpot parallel to the Salesforce "key separation across two trust boundaries" control: the request path and the credential store each prove themselves independently before any data moves.
Revocation and deletion
- Uninstall: When a customer uninstalls the app, HubSpot revokes the tokens on its side immediately — they stop working everywhere, including in RGA. RGA additionally purges its stored (encrypted) copies on receiving HubSpot's signed
app.uninstalledwebhook, verified with HMAC-SHA256 over the exact request bytes. The connection row is retained as an audit record (who/when), with the credentials cleared. - Admin disconnect: An admin can sever the connection from the RGA web app at any time. This purges RGA's stored tokens and invalidates the cached access token. (Fully removing the app from the portal is done from HubSpot's Connected Apps screen.)
- Retention: Operational content is retained for 90 days after cancellation, then permanently deleted by an automated, audited process. Deletion is RGA-side only; RGA never deletes or alters records in your HubSpot portal.
Data security
- In transit: all communication uses HTTPS/TLS.
- What RGA reads: the contact fields needed to prepare for a meeting (name, title, company, contact details) plus the RGA-managed custom properties it writes results back to. On lead records, RGA reads the lead only to find its associated contact; the prep itself runs against that contact.
- What RGA writes: the meeting-prep result fields on the contact record (
rga_last_prep_session,rga_last_prep_date,rga_prep_doc_url,rga_sync_status) and the standard contact fields the rep reviewed. - Cross-tenant guard: every meeting-prep record is bound to a tenant; a request for a record that doesn't belong to the caller's tenant returns "not found" (it never confirms the record exists to another tenant).
- AI processing: your HubSpot data is processed to generate outputs and is never used to train AI models.
Privacy and compliance
The platform-wide policies apply uniformly; the HubSpot integration inherits them. See the Trust & Security Center for GDPR (RGA is a Data Processor; DPA available; data-subject requests honored within 30 days), SOC 2 status, US data residency with SCCs for non-US transfers, the sub-processor list, and the incident-response commitment (affected-customer notification within 72 hours of confirming a breach).
Note for the security reviewer: this page describes controls RGA runs today. For a security questionnaire, data-flow diagram, incident-response plan, or DPA, email support@revenuegrowthagent.com.