Skip to main content

Connected Apps

Vulkro inspects every *.connectedApp-meta.xml (SFDX) and *.connectedApp (MDAPI) file. Connected Apps define the OAuth contract that external systems use to talk to your Salesforce org, so findings here directly affect federated authentication posture.

Full OAuth scope

<oauthConfig>
<scopes>Full</scopes>
<scopes>RefreshToken</scopes>
</oauthConfig>

The Full scope grants an access token everything the authorizing user can do. Vulkro emits at High severity. Replace with the specific scopes the integration needs: Api, RefreshToken, OpenId, etc. Pair the remaining scopes with Enforce IP restrictions and a short token lifetime in Setup.

Cleartext callback URL

<callbackUrl>http://localhost:8080/oauth/callback</callbackUrl>

The OAuth authorization code returned to this URL travels unencrypted, allowing an on-path attacker to intercept the code and exchange it for an access token (CWE-319, authorization-code interception). Vulkro emits at High severity. Change the callback to https://. The OAuth provider (Salesforce) cannot enforce TLS at the redirect target; that is the integrating app's responsibility.

Hardcoded <consumerSecret>

<consumerKey>3MVG9YDQS5WtC11oOXz7BaqUgw8</consumerKey>
<consumerSecret>1234567890ABCDEFGHIJ</consumerSecret>

Salesforce generates the consumer secret and is supposed to be the only system that knows it. A literal value in deployable metadata is a leaked OAuth client secret: anyone with repository or deploy- artefact access now holds it. Vulkro emits at Critical for the secret and at Medium for the consumer key (which is the OAuth client_id, less secret but still per-org).

Remove both elements from the metadata. Configure the Connected App in the target org's Setup once at deploy time and rotate the leaked secret immediately. Use a Custom Metadata Type or Named Credential to look up the per-org key at runtime.

The rule skips template placeholders that look like a CI pipeline is going to inject the value at deploy time:

<consumerKey>{{client_id}}</consumerKey>
<consumerSecret>REPLACE_ME</consumerSecret>

{{var}}, ${var}, <% var %>, and the literals REPLACE_ME, TODO, TBD, placeholder, your_secret_here, and all-x / all-0 strings are recognised and not flagged.

What is not covered yet

  • Certificate-based auth: Vulkro does not yet emit a finding when a service-to-service Connected App relies on Password auth where a JWT Bearer flow with a certificate would be appropriate.
  • IP restrictions and login policies are configured in the platform Setup and are outside the deployable metadata's reach.