Salesforce Heroku Connect detection
Vulkro's Heroku Connect detector pack
(src/security/sf_heroku_connect.rs) covers the bridge between a
Salesforce org and a Heroku Postgres database. Heroku Connect
replicates SObjects bidirectionally based on a JSON mapping
configuration; the questions this detector pack answers are whether
sensitive fields land on the Heroku side encrypted, whether
write-back resolves conflicts, and whether the connection URL or
REST API token is committed in plaintext.
The detector activates when the project root contains any of three canonical markers:
- a
mapping.json(any path) carrying bothconnection_nameandobject_namekeys (the Heroku Connect mapping shape) - a
Procfiledeclaring aheroku-connect:worker - an
app.json(orapp.yml/app.yaml) referencing theherokuconnectadd-on
A project with none of the three markers returns zero findings without entering the per-rule code paths.
Rules
| ID | Severity | What it catches |
|---|---|---|
| HC-001 | High | Heroku Connect mapping replicates a sensitive Salesforce field (SSN__c, DateOfBirth, Patient_MRN__c, bank_account__c, medical_record_number__c, and similar) into Heroku Postgres without a transform rule or mapped_field_name masking. The default Heroku Connect sync is a verbatim column copy, so the regulated value lands in the salesforce schema in cleartext. HIPAA, PCI, and GDPR controls that apply on the Salesforce side do not extend to the Postgres copy unless configured explicitly. |
| HC-002 | High | A SQL migration or schema.sql references a Heroku Connect mapped column against the salesforce schema, but no pgcrypto extension, pgp_sym_encrypt(...), or crypt(...) call sits anywhere in the project's SQL. The sensitive Salesforce value persists on Heroku in cleartext; a Postgres backup or pg_dump artefact carries the raw regulated data. |
| HC-003 | Medium | Mapping enables Salesforce write-back ("write_to_salesforce": true) but does not declare a "resolve_conflicts" strategy ("newer_record_wins", "salesforce_wins", "postgres_wins", etc). A concurrent edit on the Salesforce side and the Heroku side produces an orphan or silently overwritten record. |
| HC-004 | High | A literal postgres://user:password@host:port/db connection URL committed in app.json, app.yml, config-vars.json, or a Heroku Connect configuration file. Heroku app configs in the repo are readable by anyone with checkout access; a plaintext password is a same-day rotation incident. |
| HC-005 | Medium | A literal Heroku Connect REST API token (connection_string, bearer, or X-HC-API-Token value) committed in source. The REST API authenticates via a bearer token that carries full control over the mapping configuration; a leaked token lets an attacker reshape the bidirectional sync, add their own mapping, or exfiltrate Salesforce data to a Postgres they control. |
Pro gate
Pro-only. Gated by license::Feature::HerokuConnect. The
vulkro scan invocation detects Heroku Connect markers in the
project and prompts for a Pro license before running the HC-* rules.
Heroku Connect projects are often standalone Node, Java, or Ruby
apps with no Apex sources on the same machine, so the gate is wired
at the scan entry independently of the language list. Native
scanners for the project's other languages still run.
Example finding
Severity: High
Rule: HC-001
File: heroku-connect/mapping.json
Line: 42
Message: HC-001: Heroku Connect mapping in
`heroku-connect/mapping.json` replicates the sensitive
Salesforce field `SSN__c` into Heroku Postgres without
a `transform` rule or `mapped_field_name` masking. The
default Heroku Connect sync is a verbatim column copy,
so the regulated value lands in the `salesforce`
schema in cleartext (CWE-311). HIPAA, PCI, or GDPR
controls that apply on the Salesforce side do not
extend to the Heroku Postgres copy unless you
configure them explicitly.