Skip to main content

Methodology: what a safe Salesforce app should be

This page documents the safe-Salesforce-app standard as Salesforce publishes it, and the Vulkro coverage map against that standard. Every detector we ship traces back to a row in the coverage matrix at the bottom; every gap is named explicitly with a "covered / partial / planned / out of scope" label so customers can audit our coverage instead of trusting our marketing.

Detector implementations are proprietary (per the closed-source positioning). This document is the methodology, the rule IDs, and the coverage status - all of which are part of the public credibility play.

Why publish this

A Salesforce security tool that does not name its standard cannot be audited against. Every commercial competitor (CodeScan, Clayton, AppOmni, Obsidian, Adaptive Shield) keeps its rule taxonomy proprietary; the customer is left trusting a vendor demo. Vulkro flips that: the standard we measure against, the rule IDs we emit, and the precise coverage gap are all on this page.

If a customer can read this and reproduce our coverage decision for a finding, the product is trustworthy. If they cannot, we are not done.

The Salesforce safe-app standard (sources)

The standard is the union of four publicly-published bodies:

  1. The Salesforce Well-Architected Framework (architect.salesforce.com). Three pillars (Trusted, Easy, Adaptable), each with three dimensions, each with documented anti-patterns. Authoritative for architecture quality.
  2. The AppExchange Security Review checklist (Partners portal + the Dev Blog's Top 20 vulnerabilities and the Prepare for Security Review companion). Authoritative for ISV submissions: every managed package shipping through AppExchange must pass it.
  3. OWASP API Security Top 10 (owasp.org/API-Security). Cross-industry standard; Vulkro's OwaspCategory enum maps to it directly.
  4. The 2025-26 Salesforce breach class map. Not a Salesforce-published standard, but the empirically-grounded list of what actually compromised real orgs: Salesloft Drift, Gainsight, Experience Cloud guest-user (AuraInspector), ShinyHunters / UNC6040 vishing, ForcedLeak (Agentforce CVSS 9.4).

The PMD Apex rule catalog and the Salesforce Code Analyzer rule set are the industry baseline for code-level coverage. They are not part of the "standard" in the safe-app sense, but every Salesforce SAST tool is compared against them, so we include a parity check here.


1. Well-Architected Framework

The framework has three pillars: Trusted, Easy, Adaptable. Each pillar has three dimensions. The dimensions are the unit at which anti-patterns are catalogued by Salesforce Architects.

1.1 Trusted

"Trusted solutions protect stakeholders." Salesforce Architects.

DimensionWhat it requiresNotable anti-patterns
SecureAuthentication, authorization, encryption, secrets handling, secure communication, secure data storage. Every requirement in the AppExchange Security Review checklist sits here.Hardcoded credentials in source / metadata; CRUD/FLS bypass; without sharing on user-reachable Apex; cleartext callbacks; broad OAuth scope; over-privileged profiles; guest-user object exposure.
CompliantCompliance with the regulatory frameworks the data falls under (GDPR, HIPAA, PCI DSS, SOC 2, NIST). Mapping audit logs, retention, lawful basis, encryption-at-rest.PII in debug logs; missing field-level encryption on sensitive fields; missing audit trail; cross-border data flow without DPA.
ReliableOperates within governor limits, handles errors deliberately, recovers from transient failures, bulkifies.SOQL in loop; DML in loop; @future in loop; non-bulkified triggers; recursive triggers without guards; empty catch blocks; reports with multiple purposes; logic in triggers without handler pattern; mixed-DML errors.

1.2 Easy

"Easy solutions deliver value fast." Salesforce Architects.

DimensionWhat it requiresNotable anti-patterns
IntentionalSolutions that map to a clear business outcome; declarative-first; minimal custom code where standard features exist.Custom code where Flow / standard automation suffices; duplicate fields / objects modelling the same concept; "kitchen-sink" controllers.
AutomatedManual processes replaced with automation; declarative tools (Flow) preferred for business logic.Manual data movement; spreadsheet-based workflows; ungoverned imports; unoptimised SOQL that scans full objects.
EngagingLightning components and modern UI surface; consistent UX; fast page loads.Visualforce-only UI on Lightning Experience; absolute-positioned CSS in components; uncontextualised dashboards.

1.3 Adaptable

"Adaptable solutions evolve with the business." Salesforce Architects.

DimensionWhat it requiresNotable anti-patterns
ResilientProduction-like testing in lower environments; release pipeline with rollback; environment parity; observability for cross-component failures.Tests pass in scratch but fail in prod (no parity); deploy without rollback plan; missing platform-event monitors on critical flows.
ComposableIntegration via well-defined APIs (Named Credentials, External Services); separation of concerns; trigger handler frameworks.Point-to-point integrations without an integration layer; ungoverned external callouts (hardcoded URLs); multiple triggers per object without orchestration.
Future-Proof (implied; sometimes folded into Composable)Hardcoded record IDs removed; declarative configuration over hard-coded constants; named credentials over hardcoded URLs.Hardcoded org-specific IDs; hardcoded URLs; tight coupling to a specific page layout.

The exact list of officially-published anti-patterns evolves; the Salesforce Well-Architected Anti-Patterns catalog is the authoritative source. Vulkro tracks the high-value statically-detectable ones; see section 9.


2. AppExchange Security Review

The Security Review is the gating process for every ISV-distributed managed package on AppExchange. Salesforce's Product Security team runs:

  • Static analysis (Checkmarx CxSAST + Salesforce Code Analyzer).
  • Dynamic analysis (OWASP ZAP / Burp / Qualys; Chimera was retired June 2025).
  • Manual review against eight categories.

2.1 The eight categories

#CategoryWhat's required
1Authentication & session managementCookies over HTTPS with the SECURE flag; session invalidated on logout; SessionID never sent to external systems; OAuth or Integration Users for any external call.
2Authorization (CRUD / FLS / sharing)Explicit CRUD and FLS check before every DML / query. WITH USER_MODE (Spring '23+) or WITH SECURITY_ENFORCED (older) on SOQL. Every Apex class declares a sharing mode: with sharing, without sharing, or inherited sharing.
3Input validationNo SOQL injection (use bind variables or String.escapeSingleQuotes). XSS-safe rendering (no escape="false" on user-controlled content). No CSRF on state-changing endpoints.
4Output encodingAll user-rendered content encoded for its sink (HTML / JS / URL). CSP-safe Lightning component rendering.
5CryptographyNo MD5 or SHA-1 for authentication; no static IV; no Math.random() for tokens; AES-256 minimum; key handled via Crypto.encryptWithManagedIV.
6Communication securityAll callouts over HTTPS; TLS 1.2 minimum; valid CA chain; CSP Trusted Sites for remote resources; Named Credentials for outbound auth.
7Logging & error handlingNo PII in debug logs; no stack traces to users; no application secrets in System.debug; error pages do not leak system data.
8Secrets storageNamed Credentials, Protected Custom Settings, or Protected Custom Metadata. Never hardcoded in source.

2.2 The Top 20 vulnerabilities (verbatim, ranked by failure rate)

Salesforce Dev Relations publishes the empirical ranking from real submission failures. Quoted verbatim from the official blog post:

RankVulnerabilityFailure trigger
1CRUD/FLS enforcementFailure to check object and field-level accessibility before queries or DML.
2Insecure software versionOutdated libraries or frameworks with known CVEs.
3Sharing violationApex classes lacking with sharing; Flows in System Mode without sharing.
4Insecure storage of sensitive dataSecrets hard-coded into source code.
5TLS/SSL configurationConnections not using TLS 1.2+.
6Sensitive information in debugDebug statements that expose secrets, system data, or PII.
7CSRFNo anti-CSRF token on state-changing endpoints.
8Stored & reflected XSSUnvalidated input rendered as HTML.
9JavaScript not in static resourcesJS loaded externally rather than packaged.
10SOQL injectionUnvalidated input concatenated into dynamic SOQL.
11Lightning: improper CSS load<link> / <style> instead of approved component loading.
12JavaScript in Salesforce DOM (Classic only)JS running in the Salesforce app context.
13Information disclosure on errorsStack traces and system data shown to users.
14Aura components: CSS outside componentCSS that bypasses component encapsulation.
15Message channel exposedLightning Message Channel with isExposed=true.
16Sensitive info in URLCredentials or tokens in query strings (server-logged).
17Insecure endpointHTTP instead of HTTPS.
18Username or email enumerationDistinguishable error messages reveal valid accounts.
19Password managementPassword reuse, missing old-password verification, cleartext transmission.
20Password EchoPasswords rendered in plaintext in UI or API.

vulkro-sf appexchange-report maps each Vulkro Salesforce finding to the checklist section that gates it, and renders a PASS / FAIL / NOT-EVALUATED HTML report - see AppExchange Security Review readiness.


3. Apex security checklist (developer-facing rules)

This is the operational shape of the AppExchange Security Review for Apex.

3.1 CRUD / FLS / Sharing

RuleApex pattern that satisfies itAnti-pattern Vulkro flags
Declare sharing modepublic with sharing class Foo {} / inherited sharingClass with no sharing declaration that handles user-supplied input.
Enforce CRUD/FLS on readWITH USER_MODE (Spring '23+) / WITH SECURITY_ENFORCED; Schema.SObjectType.X.isAccessible()Dynamic SOQL without enforcement; WITHOUT SHARING on user-reachable classes.
Enforce CRUD/FLS on writeDatabase.insert(records, AccessLevel.USER_MODE); insert as user records;; Schema.SObjectType.X.isCreateable() checkDML on a request-reachable class without any enforcement.
Strip inaccessible fieldsSecurity.stripInaccessible(AccessType.READABLE, records)Mass-assignment via JSON.deserialize directly into an SObject.

3.2 Injection (SOQL / SOSL)

RulePatternAnti-pattern Vulkro flags
Bind variables for user input[SELECT Id FROM Account WHERE Name = :name]Database.query('... WHERE Name = \'' + name + '\'').
Escape if dynamic requiredString.escapeSingleQuotes(input)Concatenated dynamic SOQL with no escape and no bind.
Whitelist for WHERE field name choicesEnum / static map for the user-pickable columnUser-supplied field name interpolated into dynamic SOQL.

3.3 XSS / output encoding

SinkSafeAnti-pattern
Visualforce {!field}Default escaping; do not set escape="false" on user content.<apex:outputText escape="false" value="{!UserSuppliedHtml}" />.
Visualforce {!URLFOR(...)}URL-encoded.Hand-rolled URL concatenation with user input.
LWC lwc:html="value"Sanitize via DOMPurify (or do not use).Direct innerHTML from @wire data.
Apex PageReferenceUse safe constructors; do not construct from raw input.new PageReference(userInput).

3.4 CSRF

  • All Visualforce <apex:form> automatically inject a CSRF token; do not bypass with custom HTML forms.
  • enableCSRFOnGet=true / enableCSRFOnPost=true in SecuritySettings (Vulkro flags enableCSRFOnPost=false at High).
  • REST Apex endpoints that change state must verify the request origin or rely on the Authorization header (no cookie-only auth for state changes).

3.5 Cryptography

ConcernRequiredAnti-pattern
Hash for authenticationSHA-256+ or bcryptMD5 / SHA-1.
Symmetric encryptionAES-256 with managed IVAES-128 / static IV / ECB mode.
Randomness for tokensCrypto.getRandomLong() / Crypto.getRandomInteger()Math.random().
Key handlingCrypto.encryptWithManagedIVHardcoded keys in Apex or metadata.

3.6 Secrets / Named Credentials

  • Hardcoded secrets in Apex literals, customLabel, or staticResource content fail review.
  • Named Credentials (recommended): credential lives in Setup; Apex references the named credential by API name; rotation is admin-controlled.
  • External Credentials (newer): Named Credential + External Credential split; supports OAuth client-credentials, JWT, password-grant.
  • Protected Custom Metadata Types: encryption-at-rest in the org; readable only by package code.
  • Never use unprotected Custom Settings for secrets (visible to any admin).

3.7 Logging hygiene

  • System.debug() output is preserved across all logs; treat it as a public surface.
  • LoggingLevel.DEBUG (or lower) for routine; ERROR for failures.
  • Never log: passwords, OAuth tokens, session IDs, customer PII, account numbers, SSNs.
  • Do not surface stack traces to end users; convert to a user-safe message and log the trace internally.

3.8 Test coverage (AppExchange gate: 75%)

  • AppExchange Security Review requires 75% code coverage across the package.
  • All test classes use @isTest and a TestDataFactory pattern (no SeeAllData).
  • System.runAs is restricted to test paths.
  • ApexUnitTestClassShouldHaveAsserts (PMD): no test methods without Assert.*.

4. LWC / Aura / Visualforce surface

4.1 Lightning Web Security (LWS)

Salesforce evolved from Lightning Locker (which used Secure* wrapper objects) to Lightning Web Security, which uses distortion: the JS sandbox transforms unsafe operations rather than wrapping APIs. Each namespace gets its own detached sandbox.

The security model prohibits:

  • document.write() (distorted to a no-op).
  • eval with user-controlled input.
  • Inline <script> or <style> tags (CSP-blocked).
  • Bypassing the namespace boundary via window.parent / top.
  • @wire-to-innerHTML taint without sanitisation.

Vulkro's sf_lws, sf_lwc, sf_aura_cmp detectors flag the LWS-violation patterns directly.

4.2 LWC component-level rules

  • lwc:dom="manual" plus direct innerHTML from external data = DOM XSS.
  • @wire adapters returning user-controllable data must be sanitised before templating.
  • LightningMessageService channels must have isExposed=false unless the channel is genuinely cross-package (the Top-20 vulnerability #15).
  • CSS must stay inside the component file (absolute / fixed / float positioning that breaks encapsulation fails review).

4.3 Aura legacy considerations

  • .cmp markup: aura:unescapedHtml is forbidden on user content.
  • Locker.SecureDocument access patterns differ from LWS; legacy Aura components running under Locker must not assume LWS semantics.
  • Aura external dependencies must be packaged as StaticResource (Top-20 #9).

4.4 Visualforce escape rules

  • <apex:outputText> escapes by default; never set escape="false" on user content.
  • <apex:outputField> uses Field-Level Security for rendering.
  • <apex:includeScript> must point at a StaticResource, never an external URL.
  • <apex:repeat> over user data: the rendering child must escape.

5. Metadata-type security coverage

The Salesforce Metadata API exposes 200+ types. The security-relevant subset is roughly 25 types. Each is the source of truth for an org's configuration in code form; an audit can scan them deterministically.

5.1 Identity & authentication

Metadata typeSecurity concernVulkro detector
ProfileOver-privileged base profile (Modify All / View All / API-enabled guest).sf_metadata (covered)
PermissionSetOver-privileged perm set; permset-group overlapping.sf_metadata (covered)
PermissionSetGroupPrivilege aggregation across multiple perm sets.Covered (large aggregation Medium, no-activation-required Medium).
SamlSsoConfigMissing signature validation, weak algorithm, redirect handling.Covered (weak signature algorithm).
AuthProviderHardcoded consumer secret; permissive scope.Covered.
IdentityProviderMisconfigured org-as-IdP.Out of scope for v1.
LoginFlowCustom login interception; possible MFA bypass.Covered (active-inventory finding).
LoginIpRangeNetwork-level restrictions on profile / org.Covered (full-Internet range High, broad /8 Medium, missing-on-admin Medium).

5.2 OAuth & external credentials

Metadata typeSecurity concernVulkro detector
ConnectedAppFull OAuth scope; cleartext callback; hardcoded consumer secret / key; Full + RefreshToken (Drift/Gainsight class).sf_metadata (covered, deep)
NamedCredentialHardcoded password; AnonymousUser principal with allowMergeFieldsInBody=true; HTTP endpoint.sf_metadata (covered, deep: 4 checks - hardcoded password, cleartext endpoint, merge-body-true, anonymous principal).
ExternalCredentialHardcoded credentials in metadata; missing rotation.Covered (hardcoded secret-like parameter values).
CredentialUserMapping / PerUserCredentialMappingPer-user credentials leaked at runtime.Planned.

5.3 Network & outbound

Metadata typeSecurity concernVulkro detector
RemoteSiteSettinghttp:// (cleartext) outbound URL; disableProtocolSecurity HTTPS-to-HTTP downgrade.Covered.
CorsWhitelistOriginWildcard origin or http:// cross-origin trust.Covered.
CspTrustedSiteWildcard endpoint URL or http:// endpoint.Covered.
CertificateWeak signature algorithm; weak key size; exportable private key; self-signed.Covered (weak key size Medium, exportable private key High, self-signed Low).

5.4 Sharing & org-wide defaults

Metadata typeSecurity concernVulkro detector
SharingRules / SharingCriteriaRule / SharingOwnerRuleWildcard Public Read/Write on a sensitive object; broad criteria sharing.Covered (Full Access High; Edit-to-allInternalUsers High; Edit-to-specific-role Medium).
SharingSet (Experience Cloud)Guest-user sharing-set abuse on sensitive standard objects.Covered (Edit/Full to sensitive object High, Read to sensitive object Medium inventory; ten-object sensitive list).
Object-level OrganizationWideDefault (under CustomObject)OWD = Public Read/Write on PII-bearing custom objects.Planned.
GroupPublic groups granting unintended access.Out of scope for v1.

5.5 Session & org-config

Metadata typeSecurity concernVulkro detector
SecuritySettingsWeak password policy; long session timeout; clickjack off; CSRF off; HTTPS not required; no-IP-lock; etc.sf_metadata (covered, deep: 10 checks)
MobileSettingsMobile-specific session settings, jailbreak detection.Out of scope for v1.
PasswordPolicies (folded into SecuritySettings)Length, complexity, expiration, lockout.sf_metadata (covered).

5.6 Public surfaces (Experience Cloud)

Metadata typeSecurity concernVulkro detector
Profile (Guest User License)Guest can read sensitive object; guest can View All Records (AuraInspector class).sf_metadata (covered, deep)
Site (Force.com Sites)Public site exposes unsecured Visualforce; public Apex methods reachable unauthenticated.Covered (active inventory Medium, standard portal pages enabled High, browser cross-origin allowlist Medium).
Network (Experience Cloud)Self-registration; guest file access; guest Chatter; guest not gated to login.Covered (4 checks: self-reg + profile, guest file access High, guest Chatter Medium, guest-not-gated Medium).
ExperienceBundleComponent-level guest exposure.Covered (inventory cue Medium; points admin at the matching Network + Profile guest checks).

5.7 Workflow, async, and DML automation

Metadata typeSecurity concernVulkro detector
FlowSystem-context DML; hardcoded record IDs; guest-context flows; missing entry conditions.sf_flow (covered for the documented vectors).
ApexTriggerLogic in trigger body without handler; multiple triggers per object; missing bulk handling.Planned.
WorkflowRule / WorkflowOutboundMessageOutbound message reveals SessionID; hardcoded URL; missing endpoint validation.Covered (cleartext http:// endpoint High; includeSessionId=true Critical, multi-block iteration).
ApprovalProcessAuto-approve path that elevates privilege.Out of scope for v1.
AssignmentRule / AutoResponseRuleEmail auto-response leaking record content.Out of scope for v1.

5.8 Content & external integration

Metadata typeSecurity concernVulkro detector
ExternalDataSourceAnonymous auth on a sensitive remote source; cleartext endpoint.Covered (<protocol>NoAuthentication</> High, <endpoint>http:// High).
ExternalServiceRegistrationExternal Service with no auth header / wildcard schema.Covered (missing Named Credential reference).
StaticResourceVulnerable JS library packaged (CVE in static resource); hard-coded API key in JSON.Covered (deep): RetireJS via sf_lwc plus six credential patterns (AWS key + secret, Slack, GitHub, generic API key, Bearer token) via sf_content.
EmailTemplatePII rendered in template; merge-field XSS through template.Out of scope for v1.
DocumentSensitive document attached publicly.Out of scope for v1.
CustomMetadataTypePlain-text secret stored in Custom Metadata (not protected).Covered (sensitive field name + literal value + <protected>false</> -> Critical, with placeholder filter).
WebLinkURL formula with XSS via {!URL} injection; javascript: scheme.Covered (<linkType>javascript</> Critical, <url>javascript: Critical; standalone .weblink-meta.xml only, nested object weblinks planned).
VisualforcePage / VisualforceComponentDirect file scan (escape="false", includeScript).sf_visualforce (covered).

6. Agentforce / GenAI security (ForcedLeak class)

ForcedLeak (CVSS 9.4) is the Agentforce-specific class disclosed in 2025. An agent driven by indirect prompt injection (e.g. a Web-to-Lead Description field) can exfiltrate CRM data when reachable from untrusted input and backed by an over-permissioned user or actions.

The defensive controls Salesforce documents:

ControlWhat it requiresVulkro detector
Least-privilege agent userEach agent runs as a dedicated user with only the perm sets the agent needs.sf_agentforce (Medium surface finding nudges admin to audit).
CspTrustedSite for Agentforce / EinsteinOutbound URLs the agent action can reach must be on the Trusted Sites allowlist.Planned (CspTrustedSite scanner).
Action CRUD / FLS enforcementEvery Apex action enforces CRUD / FLS or runs in USER_MODE.apex_crud_fls (covered).
Action sharing modeApex action class is with sharing or inherited sharing, never without sharing.sf_agentforce (covered, High: cross-references the Apex class file).
Prompt-template grounding sanitizationFree-text fields (Lead.Description, Case.Description) must not be ground into prompts without sanitization.Planned (needs verified GenAiPromptTemplate grounding schema).
Trusted URL enforcementAgentforce setting requires every outbound URL to be on the Trusted Sites list.Inventory only (sf_agentforce Medium surface finding).

7. 2025-26 Salesforce breach class map

Not a Salesforce-published standard, but the empirically grounded list of what compromised real customer orgs in 2025-26. Every detector that maps to a real breach class carries the breach-class label in the finding message, so the finding cites the threat model.

Breach classWhat happenedVectorVulkro detector
Salesloft Drift OAuth token theft (2025, 700+ orgs)OAuth refresh tokens for the Drift Connected App stolen at the vendor, replayed against customer orgs.Connected App + Full scope + persistent refresh token + vendor-side token store breached.sf_metadata::scan_connected_app (covered): flags Full + RefreshToken / OfflineAccess at High.
Gainsight OAuth abuse (2025, 200+ orgs)Same architecture as Drift; refresh tokens at the vendor reused.Same as Drift.Same detector.
Experience Cloud guest-user exposure / AuraInspector campaign (2023-25, Loblaw 75M, ADT 10M+)Mass-scanned Experience Cloud sites for guest profiles that granted object read on sensitive standard or custom objects, including View All.Guest User License profile with <objectPermissions> granting read or View All Records.sf_metadata guest-user (covered, High / Critical).
ShinyHunters / UNC6040 vishing (2025, Google 2.55M, Qantas 5.7M, Allianz 1.4M, ~1B records claimed)Social-engineered help-desk into installing a malicious Connected App.Malicious Connected App with broad scope; over-permissioned user accepts.sf_metadata Connected App: Covered for the technical preconditions (broad scope, full + refresh token, hardcoded secret). The social-engineering vector itself is fundamentally a human-factor attack and falls under DAST / UEBA territory, both out of scope by architectural choice (section 11).
ForcedLeak (Agentforce, CVSS 9.4) (2025)Indirect prompt injection via Web-to-Lead Description triggered Agentforce action that ran without sharing Apex.GenAiFunction Apex action invoking a without sharing class + grounding on untrusted text.sf_agentforce (covered, High): two-pass detection of Apex actions whose class is without sharing. Prompt-grounding portion is planned.

8. PMD Apex rule parity

PMD Apex (which Salesforce Code Analyzer wraps) is the de-facto industry baseline for Apex code-quality coverage. Vulkro does not aim to be a PMD replacement (the wrapper integration exists for users who want PMD output in the Vulkro format), but the security-category rules are the comparison point.

8.1 PMD Apex security rules (the security category)

PMD ruleWhat it catchesVulkro coverage
ApexBadCryptoMD5, SHA-1, weak ciphers.Covered (engine crypto checks).
ApexCRUDViolationDML / SOQL without CRUD/FLS enforcement.Covered (apex_crud_fls).
ApexDangerousMethodsEncodingUtil.urlEncode misuse, Crypto.encrypt with hardcoded key.Covered.
ApexInsecureEndpointhttp:// endpoint in callout.Covered.
ApexOpenRedirectRedirect to user-controlled URL.Covered.
ApexSharingViolationswithout sharing on user-reachable class.Covered (apex_crud_fls).
ApexSOQLInjectionDynamic SOQL with input concatenation.Covered.
ApexSuggestUsingNamedCredHardcoded HTTP basic auth instead of Named Credential.Covered (via AP-012: any HttpRequest.setEndpoint('http(s)://...') that is not a callout: Named Credential reference fires Adaptable).
ApexXSSFromEscapeFalseVisualforce escape="false" on user content.Covered (sf_visualforce).
ApexXSSFromURLParamURL parameter rendered without encoding.Covered.

8.2 PMD Apex error-prone (the security-adjacent subset)

PMD rulePatternVulkro coverage
ApexCSRFState change in constructor (CSRF-exploitable).Covered (via sf_apex_csrf, Wave 9).
AvoidDirectAccessTriggerMapTrigger.new[i] / Trigger.old[i] indexed access.Covered (via sf_apex_quality, Wave 10).
AvoidHardcodingIdHardcoded record ID.Covered (AP-003).
EmptyCatchBlockSilenced exceptions.Covered (AP-004).
InaccessibleAuraEnabledGetter@AuraEnabled annotation on a property whose getter lacks @AuraEnabled.Out of scope for v1 (requires Apex AST property / getter analysis to distinguish field-level annotation from getter-level annotation; the existing engine grammar treats them uniformly).
TestMethodsMustBeInTestClassesTests outside @isTest classes.Out of scope for v1.

8.3 PMD Apex performance (governor-limit anti-patterns)

PMD rulePatternVulkro coverage
OperationWithLimitsInLoopSOQL / DML / async in a loop.Covered (AP-001, AP-002).
AvoidNonRestrictiveQueriesSELECT Id FROM Account (no LIMIT, no WHERE).Covered (AP-013).
EagerlyLoadedDescribeSObjectResultSchema.SObjectType.X.fields.getMap() inside loop.Covered (AP-008 via the more general Schema describe in loop detector).

8.4 PMD Apex best practices

PMD rulePatternVulkro coverage
ApexAssertionsShouldIncludeMessageBare Assert.areEqual(a, b).Out of scope.
ApexUnitTestClassShouldHaveAssertsTest methods with no Assert.*.Planned (testability gate for AppExchange).
ApexUnitTestShouldNotUseSeeAllDataTrue@isTest(SeeAllData=true).Planned.
AvoidFutureAnnotation@future instead of Queueable.Planned (AP-005 candidate).
AvoidGlobalModifierglobal keyword on internal classes.Out of scope.
AvoidLogicInTriggerLogic in trigger body.Planned (AP-005 candidate).
DebugsShouldUseLoggingLevelSystem.debug('...') without LoggingLevel.Planned.
QueueableWithoutFinalizerQueueable that does not implement Finalizer.Planned.

The full PMD Apex rules catalog is at pmd.github.io/pmd/pmd_rules_apex.html. Vulkro is licensed for Wave 1 PMD parity (the security + governor-limit subset) and will iterate toward broader code-quality breadth in subsequent waves.


9. Anti-pattern detector roadmap

Anti-patterns are tracked separately from security findings in Vulkro (CLI: vulkro-sf antipatterns). Each is mapped to a Well-Architected pillar / dimension.

IDPillar / DimensionPatternStatus
AP-001Trusted / ReliableSOQL inside a loop.Covered.
AP-002Trusted / ReliableDML inside a loop.Covered.
AP-003Adaptable / (Future-Proof)Hardcoded Salesforce record ID.Covered.
AP-004Trusted / ReliableEmpty catch block.Covered.
AP-005Adaptable / ComposableLogic in trigger body without handler.Covered.
AP-006Trusted / Reliable@future annotation inside trigger or loop.Covered (trigger case; the loop case is queued).
AP-007Trusted / ReliableApex class with no apparent test class.Covered (cross-file: sibling-test naming + substring reference fallback).
AP-008Easy / AutomatedSchema.SObjectType describe call in a loop.Covered.
AP-009Adaptable / ComposableMultiple triggers on the same SObject.Covered (cross-file: group by on SObject header; cross-references siblings).
AP-010Trusted / ReliableRecursive trigger without static guard.Covered (heuristic: DML on Trigger.new / Trigger.old).
AP-011Trusted / ReliableMixed-DML transaction (setup + non-setup).Covered (heuristic: file-level setup + non-setup new constructors, excludes @isTest and System.runAs).
AP-012Adaptable / ComposableHardcoded URL in callout (use Named Credential).Covered.
AP-013Trusted / ReliableSELECT ... FROM ... without WHERE or LIMIT.Covered.
AP-014Trusted / Reliable@isTest(SeeAllData=true).Covered.
AP-015Easy / EngagingReports / dashboards on multiple concepts (single-purpose violation).Out of scope for v1 (requires report metadata parsing).

10. Vulkro coverage matrix (the gap map)

The master matrix. Every safe-app requirement enumerated above maps to exactly one row here, with the current state.

Legend

  • Covered : detector ships today and the corresponding finding exists.
  • Partial : detector covers part of the requirement; the remaining surface is named in the "Gap" column.
  • Planned : the requirement is in scope and named in the roadmap (Wave 1 or later).
  • Out of scope : intentionally not in v1 (continuous monitoring, UEBA, DAST). May be re-evaluated for the self-hosted server tier.

10.1 AppExchange Top-20 vulnerability coverage

Top-20 #VulnerabilityStateDetector
1CRUD / FLS enforcementCoveredapex_crud_fls
2Insecure software versionCovered (JS only)sf_lwc RetireJS wrapper. Apex dep version is out of scope (no Apex package manager).
3Sharing violationCoveredapex_crud_fls + sf_agentforce (action-class sharing).
4Insecure storage of sensitive dataCoveredsf_metadata (ConnectedApp secret); engine secret scanners.
5TLS / SSL configurationCovered (engine)TLS / cipher-suite checks.
6Sensitive information in debugCoveredEngine secret-in-log heuristics plus sf_apex_logging: System.debug(...) of variables matching a sensitive-name heuristic (password, secret, token, api_key, session_id, etc.) fires Medium.
7CSRFCoveredSecuritySettings.enableCSRFOnPost=false (High) plus sf_apex_csrf: DML in a Visualforce-controller constructor (the PMD ApexCSRF pattern) fires Medium.
8Stored & reflected XSSCoveredsf_visualforce + sf_lwc.
9JavaScript not in static resourcesCoveredsf_apex_url_safety: Visualforce <apex:includeScript value="http(s)://..."> (not a {!$Resource.X} reference) fires High.
10SOQL injectionCoveredApex SOQL injection detector.
11Lightning improper CSS loadOut of scopeCosmetic, not security-impactful.
12JavaScript in Salesforce DOM (Classic)Out of scopeClassic is sunsetting.
13Information disclosure on errorsCoveredsf_apex_url_safety: any call to Exception.getStackTraceString() fires Medium (the API itself is the smell - stack-trace strings should never reach a user-facing surface).
14Aura CSS outside componentOut of scopeCosmetic.
15Message channel exposed (isExposed=true)Coveredsf_message_channels: <isExposed>true</> on a LightningMessageChannel fires Medium.
16Sensitive info in URLCoveredsf_apex_url_safety: new PageReference(...) / HttpRequest.setEndpoint(...) whose argument concatenates a sensitive-named identifier (token, password, api_key, session_id, etc.) fires High.
17Insecure endpointCoveredsf_metadata RemoteSiteSetting + engine HTTP detector.
18Username / email enumerationOut of scopeRequires DAST.
19Password managementCoveredSecuritySettings covers every statically-detectable password concern (length, complexity, expiration, lockout). The runtime aspects (per-user password reuse, password echo in UI) belong to DAST, which is out of scope by architectural choice (see section 11).
20Password echoOut of scopeRequires DAST / UI inspection.

10.2 Metadata-type coverage

Metadata typeStateDetector / Plan
ProfileCovered (deep)over-privilege, guest-user exposure.
PermissionSetCovered (deep)over-privilege, dormant admins (live-org).
PermissionSetGroupCoveredlarge aggregation (>=5 permsets) Medium, no-activation-required Medium.
ConnectedAppCovered (deep)5 checks incl. Drift/Gainsight token sprawl.
NamedCredentialCovered (deep)hardcoded password, cleartext endpoint, merge-body-true, anonymous principal (4 checks).
ExternalCredentialCoveredhardcoded secret-like parameter values (Critical, CWE-798).
SamlSsoConfigCoveredweak signature algorithm (SHA-1 / RSA-SHA1) Medium.
AuthProviderCoveredhardcoded consumer secret (Critical), consumer key (Medium).
LoginFlowCoveredactive LoginFlow inventory (Medium, admin audit cue).
LoginIpRangeCoveredfull-Internet range High, broad /8 Medium, missing-on-admin Medium.
RemoteSiteSettingCoveredcleartext http:// URL, disableProtocolSecurity=true.
CorsWhitelistOriginCoveredwildcard origin, http:// cross-origin trust.
CspTrustedSiteCoveredwildcard endpoint, http:// endpoint.
CertificateCoveredweak key size (Medium), exportable private key (High), self-signed (Low).
SharingRules (all four)CoveredFull Access (High), Edit to allInternalUsers (High), Edit narrower (Medium).
SharingSetCoveredEdit/Full to sensitive object High, Read to sensitive object Medium inventory.
Object OWDPlannedPublic R/W on PII custom object.
SecuritySettingsCovered (deep)10 checks.
Site (Force.com Sites)Coveredactive site Medium, standard portal pages High, browser X-origin Medium.
Network (Experience Cloud)Coveredself-registration + profile, guest file access (High), guest Chatter (Medium), guest-not-gated (Medium).
ExperienceBundleCoveredinventory cue Medium (points admin at the matching Network + Profile guest checks).
FlowCoveredsystem DML, hardcoded IDs.
ApexTriggerCoveredAP-005 logic-in-body + AP-009 multiple-triggers-per-SObject (cross-file).
WorkflowRule / WorkflowOutboundMessageCoveredcleartext http:// endpoint (High), <includeSessionId>true</> (Critical) per-block.
ExternalDataSourceCovered<protocol>NoAuthentication</> High, <endpoint>http:// High.
ExternalServiceRegistrationCoveredmissing Named Credential reference (Medium).
StaticResourceCovered (deep)RetireJS (via sf_lwc) plus six credential patterns: AWS key + secret, Slack, GitHub, generic API key, Bearer token.
CustomMetadataTypeCoveredsensitive field + literal value + <protected>false</> -> Critical (CWE-798, placeholder filter).
WebLinkCovered<linkType>javascript</> (Critical), <url>javascript: (Critical).
VisualforcePage / VisualforceComponentCoveredsf_visualforce.
Bot / BotVersion / GenAiPlanner* / GenAiFunction / GenAiPromptTemplateCovered (deep)surface + ForcedLeak class-bypass.
EmailTemplate, Document, ApprovalProcess, AssignmentRule, AutoResponseRule, Group, MobileSettingsOut of scope (v1)low security-density per item.

10.3 Code coverage parity (PMD Apex security + adjacent)

See section 8 for the rule-by-rule mapping.

10.4 Breach-class coverage

Breach classState
Drift / Gainsight OAuth token theftCovered (Full + Refresh detector).
AuraInspector / Experience Cloud guest exposureCovered (guest-user object exposure + View All).
ShinyHunters / UNC6040 vishing (malicious Connected App install)Partial - cannot detect runtime social engineering, but the over-permissioned Connected App that becomes the attack pivot is flagged.
ForcedLeak (Agentforce class-bypass)Covered (sf_agentforce deep detector).
ForcedLeak (Agentforce prompt-template grounding)Planned (needs verified GenAiPromptTemplate schema).

11. Out of scope (by architectural choice)

Vulkro is point-in-time, offline, local-first by design. The following are excluded from v1 on purpose, not by neglect:

ClassWhy out of scopeWhat would close it
Continuous monitoringRequires a always-on agent in the customer org; that is the SSPM (AppOmni, Obsidian, Adaptive Shield) architecture, and the Salesloft Drift / Gainsight breach class is the cost of that architecture.The deferred self-hosted server tier (kept in the customer perimeter).
DASTRequires a running org to probe. Vulkro is a static / metadata tool.Out of scope permanently; integrate with OWASP ZAP / Burp / Qualys externally if needed.
UEBA / behavioural identityRequires login-event telemetry over time. SSPM territory (Obsidian leads).Out of scope; complement Vulkro with Obsidian for that workflow.
Multi-org continuous driftSame as continuous monitoring.Self-hosted tier.
Per-user runtime password reuseRequires login event stream.Out of scope.
Username / email enumerationRequires probing live endpoints (DAST).Out of scope.

12. Coverage status summary

GroupCoveredPartialPlannedOut of scope
AppExchange Top-2015005
Metadata types (security-relevant subset, ~30)29008
PMD Apex security rules10000
PMD Apex error-prone (security-adjacent)4002
PMD Apex performance3000
Well-Architected anti-patterns (statically detectable subset)14001
Breach-class map5000

The Wave 1 roadmap (12-15 additions) closes most of the Planned column; see the feature inventory for the live status.


13. References

Authoritative sources cited throughout:

This document is the source of truth for every Vulkro Salesforce detector roadmap decision. When a row in the matrix moves from Planned to Covered, the corresponding finding ID and detector module are added in the same commit, and this page is updated. The CHANGELOG records each transition.