ASIST is a regex-based, blazing-fast Static Application Security Testing (SAST) tool for securing Salesforce apps at developer speed.
Originally built for internal use at Certinia to support Security Reviews, we have now decided to release it to the community 🌍
go install github.com/certinia/asist@latest
See installing VS Code extension
go
and make
make install
Alternatively:
make
GOOS=windows GOARCH=amd64 go build -o asist.exe .
make build-binaries
To see the help, run:
asist -h
Usage:
asist [OPTIONS] [Path]
Application Options:
-u, --repo-url= URL of the repo. Used for baseline scan output
-c, --config= JSON or YAML config file to read from
-r, --rules= Rules comma separated to run (ignore rules enabled/disabled in config)
-l, --list-rules List rules which would be run
-b, --baseline-scan For getting output of ASIST baseline scan as count of occurrences and false positive occurrences, number of custom rules occurrences, type of record and this data is used for creating
metrics.
-j, --cicd-rules For use in CI/CD pipelines. Tells ASIST to only run the CICD rules defined in config file. If there are no CI/CD rules defined, no rules will be executed. If there are any occurrences, returns
a non-zero exit code which will make the pipeline step fail
-v, --verbose Print out debug messages with time elapsed since last message
-V, --version Display the current version of ASIST binary
Help Options:
-h, --help Show this help message
Arguments:
Path: Path to the file or folder to scan
Recursively scan the current working directory with default settings (all rules):
asist .
This scan produces the following output, indicating the total number of issues identified, the start and end timestamps, and the detailed findings:
{
"Count": 161,
"Started": "2025-07-23 13:12:08.231779 +0200 CEST m=+0.000501126",
"Ended": "2025-07-23 13:12:08.307712 +0200 CEST m=+0.076432459",
"Result": [
{
"ID": "ApexClassNoSharing",
"Name": "Apex Class No Sharing",
"Description": "Use of Apex classes where the sharing clause is not specified may cause confusion for other developers. Always set the most restrictive sharing clause for each class.",
"Severity": "Medium",
"RuleCategory": "Security",
"Occurrence": {
"File": "/Users/shaundoyle/sandbox/product/asist/files/testData/testFile.cls",
"Line": "Class TestFile {",
"LineNumber": 1,
"ColumnRange": [
0,
14
]
}
},
{
"ID": "XSSFormAction",
"Name": "Potential XSS with formaction in JS context",
"Description": "Use of the formaction attribute in JavaScript context may introduce an XSS issue. Consider removing it, otherwise ensure that no user input is rendered unescaped.",
"Severity": "High",
"RuleCategory": "Security",
"Occurrence": {
"File": "/Users/shaundoyle/sandbox/product/asist/integrationtests/src/aura/aura.cmp",
"Line": " \u003cform id=\"test\"\u003e\u003c/form\u003e\u003cbutton form=\"test\" formaction=\"javascript:alert(1)\"\u003eX\u003c/button\u003e",
"LineNumber": 3,
"ColumnRange": [
47,
70
]
}
},
[...]
Scan a single file with default settings:
asist force-app/main/default/classes/MyClass.cls
Print the ASIST version
asist -V
Scan a file with your config:
asist -c ./.asist.json force-app/main/default/classes/MyClass.cls
Scan with a single rule:
/asist -r ApexClassNoSharing .
Just list enabled rules, but don’t scan:
asist -l
asist -c .asist.yaml -l # Does not list rules disabled in your config
Run in verbose mode (for debugging):
asist -v .
Run in CI/CD mode (will only run rules added to cicdrules
if this property is defined):
asist -j .
Run in baseline mode:
asist -b -u "https://github.com/certinia/asist.git" .
Most of the configuration required for your project will be defined in a configuration file.
ASIST supports YAML or JSON config files.
When scanning a folder, ASIST will automatically detect either .asist.yaml
or .asist.json
from the top-level folder being scanned.
Configuration files can also be explicitly specified using the -c
argument (note that this is required when scanning a single file).
Within the config file, you can:
See our example config file for a walkthrough of all config options.
Users can override certain properties of standard rules according to their needs, allowing them to customize the behavior of specific rules by:
enabled
severity
includepattern
excludepattern
In addition to customizing standard rules, users can also create custom rules to define their own regex pattern:
customregexrules:
NoDebugStatements:
name: doNotDebug
description: "Debug statements anticipate bugs; avoid bugs instead"
enabled: false
severity: Critical
rulecategory: Security
pattern: "System\\.debug\\("
includepattern: "\\.cls$"
excludepattern: "Test\\.cls$"
You can test this specific rule like this:
asist -c .asist.yaml -r doNotDebug <file>
ASIST provides the ability to mark false positives with annotations, comments, or any other places where arbitrary text can be specified.
In the example below, the SessionIDApex
rule is ignored for the statement:
// asist-ignore-begin:[SessionIDApex]
ID sid = UserInfo.getSessionID();
// asist-ignore-end
Various rule IDs may be comma-separated to ignore multiple rules for a particular block of code, and comments with justifications can be set after the asist-ignore-begin
statement:
// asist-ignore-begin:[SessionIDApex,InsecureCryptoAlgorithm] This code is for testing, and not part of the package
ID sid = UserInfo.getSessionID();
Blob sidBlob = Blob.valueOf(sid);
Blob hash = Crypto.generateDigest('MD5', sidBlob);
[...]
// asist-ignore-end
In markup languages, comments should be set in <!-- comments -->
when possible.
In any other file types, the user must figure out the more appropriate way to insert the asist-ignore-begin
and asist-ignore-end
statements. Technically, it doesn’t matter where you put them!
Note: Nested false positive tags are not supported.
CI/CD mode is enabled using the -j
flag:
asist -j .
In this mode, by default, all enabled runs will be run if cicdrules
property is not defined, but if the cicdrules
config property contains any rule IDs, only these will be run. And, if cicdrules
is defined but is blank (no rule is mentioned under this property), then no rules will be executed.
cicdrules:
- "XSSLabel"
- "XSSMergeField"
This allows developers to add a subset of the overall ruleset to ASIST to their CI/CD pipelines, and gradually add more rules to CI/CD as they start clearing out findings for other rules. This prevents any issues for rules defined in cicdrules
from creeping back into the codebase.
This mode is intended for SecOps teams to create benchmarks across multiple projects and measure the adoption of ASIST.
Some overrides in config, such as severity, will be ignored to normalize data for apples-to-apples comparison between different code bases, and false positive findings will be included in the output.
Baseline mode is enabled by means of the -b
flag.
It’s also recommended to specify a repository URL with the -u
flag:
asist -b -u "git@github.com:certinia/asist.git" .
This command will output a JSON like this (when formatted):
[
{
"RepositoryName": "certinia/asist",
"RepositoryURL": "git@github.com:certinia/asist.git",
"RecordType": "Finding",
"Content": {
"FindingID": "b17fe249915712219aca7e",
"IsCustom": false,
"IsFalsePositive": true,
"RuleID": "LwcNonStandardPositioning",
"Severity": "Medium",
"RuleCategory": "Security"
}
},
{
"RepositoryName": "certinia/asist",
"RepositoryURL": "git@github.com:certinia/asist.git",
"RecordType": "Finding",
"Content": {
"FindingID": "3a2861bee641864816b86d",
"IsCustom": false,
"IsFalsePositive": true,
"RuleID": "LwcNonStandardPositioning",
"Severity": "Medium",
"RuleCategory": "Security"
}
}
]
A few differences can be observed compared to regular scans:
FindingID
, which is effectively a hash that uniquely identifies the finding based on the rule, the finding location, and if it’s a false positive or not.By default, ASIST will ignore files and folders defined inside .gitignore and .forceignore. If you don’t want ASIST to respect .gitignore and .forceignore, you can use the following properties in the config file:
Exit code | Exit Reason |
---|---|
0 | ASIST executed successfully with no findings |
1 | ASIST executed successfully with findings |
3 | ASIST failed due to internal error (file a bug report!) |
4 | ASIST failed due to user error (review input and config) |
Using the VSCode extension is by far the easiest way to get started with ASIST. When a file is opened or saved, ASIST will scan it to identify vulnerabilities.
Just like a linter, once the scan is complete, ASIST will annotate your code with the findings and the rule description. Findings can also be found in the “Problems” tab.
Workspace scans are also supported, making it easy to run ASIST on an entire project and address all your issues on the fly!
The extension is available on the Visual Studio Code Marketplace.
ASIST commands can be run in VSCode by pressing Ctrl+Shift+P
and typing ASIST
to get the list of available commands.
Note that some commands will print results to the “Output” tab in VSCode (select ASIST
in the channel dropdown).
While using ASIST Extension, hover over the occurrence and click on Quick fix...
option, and select Mark False positive
, This will add the placeholder asist-ignore-begin
and asist-ignore-end
comments around the affected line, and fill in the relevant rule ID.
For the VSCode extension to pick up your config file automatically, the file must to be named either .asist.yaml
or .asist.json
, and must be located at the root of the workspace.
You can create a configuration file using the Create config file
command, which produces a self-documented template.
By default, ASIST looks for a config file in the root of the VSCode workspace, but if you like, you can specify a specific config file path (relative to the workspace) in the extension preferences instead – this can be useful when working with monorepos.
This extension is shipped with prebuilt ASIST binaries, but if you need to specify a specific ASIST scanner location (which is very useful for developing new features!), here’s how:
Extension settings
Workspace
tabCustom Binary Enabled
settingCustom Binary Path