OAuth scope and third-party integrations
Every Connected App, OAuth scope, and named-credential callout is a door into the org for a third party. Vulkro inspects the OAuth scope grants on Connected Apps, the principal that backs each integration, and the data that flows out through named-credential callouts, then flags the configurations that hand a third party more reach than it needs.
The unifying principle is least privilege at the integration boundary: a scope grant should be as narrow as the integration's job, gated by an admin approval step, and tied to a principal whose blast radius is bounded.
SF-OAUTH-SCOPE-001: over-broad scope with no IP constraint
Triggers when a Connected App requests the full, refresh_token, or
api OAuth scope and has no IP relaxation constraint (no IP allowlist or
login-IP range bounding where the token can be used).
Why it matters: the full scope grants the integration everything the
authorizing user can do, and refresh_token lets it keep that access
indefinitely without a fresh login. With no IP constraint, a stolen
token works from anywhere on the internet.
How to fix: replace full with the narrowest scope set the integration
actually needs, and bind the Connected App to an IP allowlist so tokens
only work from the integration's known egress addresses.
SF-OAUTH-SCOPE-002: named-credential callout forwarding request-tainted data
Triggers when a callout through a Named Credential forwards data that originates from an inbound request (request parameters, inbound REST body, or other caller-controlled input) into the outbound call to the external provider.
Why it matters: forwarding request-tainted data to a third party can leak internal identifiers or sensitive values to an external system, and in the worst case lets a caller steer the outbound request (server-side request forgery shape) by controlling what the integration sends.
How to fix: validate and allowlist the values that flow into the callout. Never pass raw caller-controlled input straight into the outbound request path; map it to a known-safe set of values first.
SF-OAUTH-SCOPE-003: refresh_token to an unverified provider
Triggers when a Connected App or OAuth flow grants refresh_token to a
provider whose identity is not verified (no pinned, trusted endpoint or
verified publisher for the destination).
Why it matters: a refresh token is a long-lived credential. Handing one to a provider you cannot positively identify means a long-lived grant to an endpoint that could be swapped or impersonated.
How to fix: drop refresh_token unless the integration genuinely needs
offline access, and only grant it to a provider whose endpoint is pinned
and verified. Prefer short-lived access tokens where the integration can
re-authenticate.
SF-OAUTH-SCOPE-004: broad Connected App scope with no admin gate
Triggers when a Connected App carries a broad scope (for example full
or api) but its authorization policy allows self-authorization rather
than requiring admin pre-approval.
Why it matters: without an admin gate, any user can authorize the app and grant it the broad scope under their own access. That bypasses the review step where an administrator would otherwise catch an over-privileged integration.
How to fix: set the Connected App to require admin-approved users, so a human reviews and assigns the integration before it can act on anyone's behalf.
SF-OAUTH-SCOPE-005: broad scope under a shared principal
Triggers when a broad OAuth scope is granted to an integration that runs under a shared or generic principal (a single integration user that many callers or systems authenticate through) rather than a dedicated, narrowly scoped identity.
Why it matters: a shared principal collapses the audit trail and widens the blast radius. A broad scope on that one identity becomes a broad scope for every system funneled through it, and a single compromise exposes all of them.
How to fix: give each integration its own dedicated principal with the minimum scope it needs, so access and audit are isolated per integration.
SF-OAUTH-SCOPE-006: rollup
SF-OAUTH-SCOPE-006 is the rollup finding for the OAuth-scope surface.
It aggregates the individual scope and integration findings above into a
single summary entry so a reviewer can see the overall OAuth posture of
the project at a glance before drilling into each specific finding.
Why it matters: integration risk is cumulative. A project with several moderately broad grants can carry more aggregate exposure than one with a single loud finding, and the rollup makes that total visible.
How to read it: use the rollup as the headline for the OAuth-integration
section of a review, then work through the underlying
SF-OAUTH-SCOPE-001 through -005 findings it references to remediate
each contributing issue.