Available since 1.14.0 (EE), with the early access flag fe_security_scan_policies
Preliminary version. The functionality may change, and an upgrade may require manual migration actions.
PT Application Inspector (PT AI) is an application security analyzer
by Positive Technologies: static code analysis, vulnerable component, configuration and secret search (white box)
and scanning of a running website (black box).
The PT AI integration connects a project to a PT AI Enterprise Server,
and a scan execution policy adds the ptai_scan job to the project’s pipelines and sets what it scans.
The job uploads the sources of the commit to the server with the aictl client,
waits for the scan, reads the verdict of the PT AI security policy and publishes the reports.
Prerequisites
For the scan to run, make sure that:
- an administrator has turned on the
fe_security_scan_policiesfeature flag as described on the Early access page; - a PT AI Enterprise Server from 5.0 to 7.0 is reachable from the runner, and you have an access token for it (see PT AI access token);
- the PT AI integration is configured and active for the project, or inherited from a group above it;
- a security policy project is linked to the project or a group above it;
- a GitLab Runner with the Docker executor is available and can pull the scan job image.
PT AI access token
- Sign in to the PT AI Enterprise Server web interface as an administrator.
- Click the gear icon in the lower-left corner to open the administration area.
- Open System settings → Access tokens.
- Click Create token.
- Enter a token name, for example
gitlab-ci-ptai, select the permission For the light agent and CI/CD plugins and set the expiry. - Confirm and copy the token.
Once the dialog is closed, PT AI no longer shows the token value. Revoke a lost token and create a new one.
The PT AI integration
Configure the integration on a project or a group, in “Settings” → “Integrations” → “Positive Technologies Application Inspector”. The form holds the server connection, the trust in its certificate and the scan job image. What is scanned, the black box and its sign-in are set in the scan execution policy.
Connection
| Field | What it sets |
|---|---|
| “Server URL” | Base URL of the PT AI server, for example https://ptai.example.com. Required |
| “API token” | The PT AI access token the job signs in with. Required |
TLS settings
| Field | What it sets |
|---|---|
| “Certificate trust” | How the scan job decides whether to trust the PT AI server: “Trust the certificates of the job image”, “Trust the certificate authority below” or “Do not verify the certificate” |
| “Certificate authority” | PEM certificate of the authority that signed the server’s certificate. Used only with “Trust the certificate authority below” |
The job hands the certificate authority to aictl as a parameter of its own. The image’s certificate store stays as it is for the job’s other commands.
Scan job image
| Field | What it sets |
|---|---|
| “Scan job image” | The image the ptai_scan job runs in: the whole reference, with a tag, a digest, or both. Required. A new integration is filled in with the image this product ships, registry.deckhouse.ru/deckhouse/ee/packages/code/images/ptai:1.2.2 |
| “Registry login” | Optional. The login for the registry the image is pulled from, or a reference to the CI/CD variable that holds it, such as $SCANNER_REGISTRY_USER |
| “Registry password” | The password or token for that registry, or a reference to the CI/CD variable that holds it. The form does not show it after saving, and the API does not return it. Left blank on save, the field keeps the saved password |
| “Expand $ in the registry login and password” | A checkbox, on by default. On: both fields are references to CI/CD variables of the scanned project or its group, written as $NAME or ${NAME}. Off: both fields hold the login and the password themselves |
Rules for the registry login and password:
- The credentials are passed only when both fields are filled in; with one of them the image is pulled without credentials. A blank password field keeps the saved password when you save the form, as for every integration secret: to remove the saved password, reset the integration.
- With the checkbox on, the variables are regular variables, not file variables, and their names cannot start with
FE_,CI_orGITLAB_. Mask the password variable. The variables must reach the scan job: see Registry credentials for the scanner image. - With the checkbox off, the values are used as they are, and any password length is accepted. For a password that contains a
$, turn the checkbox off: otherwise$...is taken for the name of a variable. - A login and password given as values are not written into the pipeline configuration. When a runner picks the scan job up, the server reads them from the integration and passes them to the runner as job credentials for the registry of the job image. The job script does not see them.
- The image this product ships is pulled without credentials.
- A change of the “Server URL” keeps the registry password: it is sent to the registry of the image, not to the PT AI server.
- After a new registry host in the “Scan job image” field, enter the password again: otherwise the integration is not saved, and the saved password stays as it was. Testing the settings checks the new registry without the password and says the saved password was not used. Another tag or path in the same registry keeps it.
A custom image needs aictl, ruby and mktemp, and curl as well when the policy reads its settings file from another project. A job whose image lacks one of these commands fails and names it.
The fields of the “Scan jobs” section are read only from the integration of the group that owns the policy, or of the closest group above it. Values on the scanned project’s integration have no effect. The server address, the token and the certificate trust come from the scanned project’s integration, its own or inherited.
Click “Test settings” to sign in to the server with the token from the form and ask for the PT AI version.
On failure, the form shows the server’s response code or the connection error.
The same check asks the registry whether the scan job image can be pulled:
with the login and password when the checkbox is off and both fields are filled in, without credentials when one of them or both are empty.
The image is not checked when the pair names CI/CD variables, which only the runner fills in, or when it is the image this product ships.
A registry that does not answer over HTTPS is asked over HTTP, as the runner pulls from a registry listed in insecure-registries of its Docker; the login and password then go unencrypted.
A registry on a local network address is checked only when an administrator turns on “Allow requests to the local network from webhooks and integrations”.
When the image cannot be pulled (access is denied, the tag or digest is missing, the registry cannot be reached from the server),
the check fails and its message names the reason. The integration can still be saved.
On success, the form shows “Connection successful.”.
Click “Save changes” to save the form.
Turning the scan on
Add a ptai action to the .deckhouse_code/security-policies/policy.yml file of the security policy project:
scan_execution_policy:
- name: PT AI everywhere
enabled: true
rules:
- type: pipeline
branches: ["*"]
actions:
- scan: ptai
variables:
FE_SCANS_PTAI_MODULES: Configuration,Components,PatternMatching,StaticCodeAnalysis
FE_SCANS_PTAI_LANGUAGES: Java,PythonThen link the policy project: for a project, under “Secure” → “Policies”; for a group, under “Settings” → “Security policy”.
The scan can also be turned on in the policy editor, with the checkbox of the PT AI scan. The editor offers it only once an active PT AI integration is set up for the project or a group above it; until then the editor shows “An active PT AI integration is required to use this scan in security policies.” with a link to set up the integration. The editor groups the scan settings into the “Scan” and “Black box” blocks; “Sign-in to the site” and “Proxy” are inside the “Black box” block.
A policy cannot set the integration’s settings. A ptai action that names FE_SCANS_PTAI_SERVER_URL,
FE_SCANS_PTAI_TOKEN, FE_SCANS_PTAI_TLS_MODE, FE_SCANS_PTAI_CA_CERT, FE_SCANS_PTAI_IMAGE,
FE_SCANS_REGISTRY_LOGIN_VARIABLE or FE_SCANS_REGISTRY_PASSWORD_VARIABLE is not saved.
The FE_SECURITY_FAIL_ON threshold is refused for ptai too: the job is failed by the security policy on the PT AI server
(see When the job fails).
The policy options are checked on save and again when the job is built, so a policy committed to the repository without the editor, with a value that is not allowed, fails the job before it reaches the server:
ERROR: this scan cannot run the configuration the policy asks for: <REASONS>Once the policy applies, every pipeline it matches gets the ptai_scan job,
in the pipeline stage the policy names, fe-security-scanner by default.
Scan
The “Scan” block is required: every scan runs at least one white-box module, and the black box is added to it.
| Field | Variable | What it sets |
|---|---|---|
| “Scan modules” | FE_SCANS_PTAI_MODULES | White-box modules, comma-separated. Default: Configuration, Components, PatternMatching, StaticCodeAnalysis, the set the PT AI server creates a new project with |
| “Programming languages” | FE_SCANS_PTAI_LANGUAGES | Languages of the project, comma-separated. Required as soon as the modules, the website address or “Do not download dependencies” is set |
| “Skip files listed in .gitignore” | FE_SCANS_PTAI_SKIP_GITIGNORE | true keeps build output and vendored trees out of the scan when the repository ignores them |
| “Do not download dependencies” | FE_SCANS_PTAI_SKIP_DEPENDENCY_DOWNLOAD | true stops the analysis kernels fetching the project’s packages, for every language. Turn it on when the PT AI server cannot reach the package registries: the download would fail the scan |
| “Settings file” | FE_SCANS_PTAI_SETTINGS_FILE | Path to a project settings file of your own (see Settings file) |
| “Settings file project” | FE_SCANS_PTAI_SETTINGS_PROJECT | The repository that holds that file, as group/project |
The editor names the modules as the PT AI documentation does:
| Value in the policy | Name in the editor |
|---|---|
StaticCodeAnalysis | “Static code analysis” |
PatternMatching | “Pattern matching” |
Components | “Vulnerable components search” |
SoftwareCompositionAnalysis | “Vulnerable components and their use search” |
Configuration | “Configuration vulnerabilities search” |
MaliciousCodeDetection | “Malicious code search” |
SecretDetection | “Secrets in code search” |
BlackBox is not in the list: the module is added on its own when a website address is set.
With no white-box module in the policy, the job takes the default modules.
The server accepts SecretDetection only together with StaticCodeAnalysis or PatternMatching;
without them the scan fails with INVALID_MODULES_FOR_SECRET_DETECTION.
Languages: Java, CSharp (CSharp (Windows, Linux)), CSharpWindows (CSharp (Windows)), Php, JavaScript, Python,
ObjectiveC, Swift, CAndCPlusPlus, Go, Kotlin, Sql, Ruby, Solidity, Scala, OneC.
The job uploads the working tree of the commit without the .git directory, the reports and security-reports directories
and the .aiproj.json file at the repository root.
Submodules and LFS objects are uploaded as the runner checked them out;
the project sets this with the GIT_SUBMODULE_STRATEGY and GIT_LFS_SKIP_SMUDGE CI/CD variables.
Black box
The “Black box” block scans the running application in the same job as the sources. The PT AI server opens the site, so the address must be reachable from it; internal addresses are allowed.
| Field | Variable | What it sets |
|---|---|---|
| “Website address” | FE_SCANS_PTAI_BLACKBOX_SITE | URL of the site, http or https. Filling it in turns the black box on. Any other black box option without a website address is not saved |
| “Search mode” | FE_SCANS_PTAI_BLACKBOX_LEVEL | How thoroughly the site is explored: Fast, Normal or Full. Default: Normal |
| “Scan scope” | FE_SCANS_PTAI_BLACKBOX_SCOPE | How far from the address the scan goes: Domain (“Domain”), Folder (“Folder”) or Path (“Path”). Default: Path |
| “Site certificate” | FE_SCANS_PTAI_BLACKBOX_SSL_CHECK | Whether the PT AI server checks the site’s certificate: true (default) or false. For a site behind a private certificate authority, add that authority to the PT AI server’s certificate store |
| “Run autocheck after the scan” | FE_SCANS_PTAI_BLACKBOX_AUTOCHECK | true runs exploits for what the static analysis found against the running site, to confirm or refute each finding. The editor turns it on for a new block |
| “Additional HTTP headers” | FE_SCANS_PTAI_BLACKBOX_HEADERS | One per line, as Name: value |
| “Allowed addresses” | FE_SCANS_PTAI_BLACKBOX_ALLOWLIST | One per line. An address without a suffix is a wildcard; address|ExactMatch is an exact match, address|RegExp a regular expression |
| “Blocked addresses” | FE_SCANS_PTAI_BLACKBOX_DENYLIST | The same form. This is where a sign-out link goes, and anything else the scan must not follow |
Every project a policy covers can read it, so the policy holds no secrets.
The password, cookie and proxy password fields take a reference to a CI/CD variable of the scanned project or its group:
$NAME or ${NAME}. The runner expands it in the job.
A policy with a literal value is not saved; variable names starting with FE_, CI_ and GITLAB_ are refused.
The Authorization, Proxy-Authorization, Cookie, X-Api-Key and X-Auth-Token headers are set the same way:
the header value must be the whole reference.
FE_SCANS_PTAI_BLACKBOX_HEADERS: |
X-Trace: on
Authorization: $PTAI_SITE_AUTHORIZATIONBearer $TOKEN is refused: keep Bearer together with the token in the PTAI_SITE_AUTHORIZATION variable.
If the variable the policy references does not exist or is empty, the job fails, for example:
ERROR: the CI/CD variable the security policy names for the sign-in password holds no value.Sign-in to the site
Without signing in, the scan sees only the pages open to anonymous visitors. The editor shows only the fields of the chosen authentication type.
| Field | Variable | For types | What it sets |
|---|---|---|---|
| “Authentication” | FE_SCANS_PTAI_BLACKBOX_AUTH_TYPE | all | none (“No authentication”, default), form (“Sign-in form”), http (“HTTP Basic”), cookie (“Cookie”) |
| “User” | FE_SCANS_PTAI_BLACKBOX_AUTH_LOGIN | form, http | The login on the site. Required |
| “Password variable” | FE_SCANS_PTAI_BLACKBOX_AUTH_PASSWORD | form, http | Reference to a masked CI/CD variable that holds the password. Required |
| “Cookie variable” | FE_SCANS_PTAI_BLACKBOX_AUTH_COOKIE | cookie | Reference to a masked CI/CD variable that holds the session cookie. Required |
| “Validation address” | FE_SCANS_PTAI_BLACKBOX_AUTH_VALIDATION_ADDRESS | http, cookie | A page only a signed-in user reaches. Required |
| “Validation template” | FE_SCANS_PTAI_BLACKBOX_AUTH_VALIDATION_TEMPLATE | form, cookie | Text that appears on that page when signed in, and does not when signed out. Required for cookie |
| “Sign-in form URL” | FE_SCANS_PTAI_BLACKBOX_AUTH_FORM_ADDRESS | form | URL of the page with the sign-in form |
| “Form detection” | FE_SCANS_PTAI_BLACKBOX_AUTH_FORM_DETECTION | form | Auto (“Automatically”, default) or Manual (“By the given fields”) for a form the scan cannot find by itself |
| “Sign-in form XPath”, “User field name”, “Password field name” | FE_SCANS_PTAI_BLACKBOX_AUTH_FORM_XPATH, FE_SCANS_PTAI_BLACKBOX_AUTH_LOGIN_KEY, FE_SCANS_PTAI_BLACKBOX_AUTH_PASSWORD_KEY | form | The form’s XPath and the names of its login and password fields, with Manual |
An action that signs in with HTTP Basic:
actions:
- scan: ptai
variables:
FE_SCANS_PTAI_LANGUAGES: Java
FE_SCANS_PTAI_BLACKBOX_SITE: https://staging.example.com
FE_SCANS_PTAI_BLACKBOX_AUTH_TYPE: http
FE_SCANS_PTAI_BLACKBOX_AUTH_LOGIN: scanner
FE_SCANS_PTAI_BLACKBOX_AUTH_PASSWORD: $PTAI_SITE_PASSWORD
FE_SCANS_PTAI_BLACKBOX_AUTH_VALIDATION_ADDRESS: https://staging.example.com/profileFor the example to work:
- Open the project or group and go to “Settings” → “CI/CD” → “Variables”.
- Create the
PTAI_SITE_PASSWORDvariable with the site password as its value, and mask it.
If the sign-in fails, the scan covers only the open pages,
and the job prints the scan errors the server returned, AuthFailed among them.
Proxy
| Field | Variable | What it sets |
|---|---|---|
| “Proxy address” | FE_SCANS_PTAI_BLACKBOX_PROXY_HOST | Host name or IP address of the proxy, not a URL. Filling it in turns the proxy on |
| “Proxy port” | FE_SCANS_PTAI_BLACKBOX_PROXY_PORT | A number from 1 to 65535 |
| “Proxy type” | FE_SCANS_PTAI_BLACKBOX_PROXY_TYPE | Http (default), Socks4 or Socks5 |
| “Proxy user” | FE_SCANS_PTAI_BLACKBOX_PROXY_LOGIN | The login on the proxy. With it, the password variable is required |
| “Proxy password variable” | FE_SCANS_PTAI_BLACKBOX_PROXY_PASSWORD | Reference to a masked CI/CD variable that holds the proxy password |
Settings file
For a setting PT AI accepts and the policy does not offer, name a PT AI project settings file of your own
(the .aiproj format). The job uploads it to the server as it is, in place of the file it builds from the policy.
While “Settings file” is filled in, the editor greys out the other settings of the “Scan” and “Black box” blocks:
the job does not read them, and they are not checked on save.
actions:
- scan: ptai
variables:
FE_SCANS_PTAI_SETTINGS_FILE: .aiproj.json
FE_SCANS_PTAI_SETTINGS_PROJECT: security/ptai-settings“Settings file” is a path from the repository root: relative, with no .. segment, no trailing /,
ASCII characters only. The file name can be anything.
“Settings file project” decides where the file comes from:
- empty: the scanned repository, at the commit being built. The project can change such a file itself, in a merge request branch too;
group/project: the default branch of that project, read with the job token. The scanned projects cannot change such a file.
For the job to read the file from another project:
- Open the project that holds the file.
- Go to “Settings” → “CI/CD” → “Job token permissions”.
- Add the scanned projects or their group.
The job fails before the scan when there is no file at the path, the file is empty, the project does not let the scanned project’s jobs in (HTTP 401 or 403) or the file is not on the default branch (HTTP 404). Passwords and cookies written into the file are visible to everyone with access to the repository.
The job does not upload the .aiproj.json file at the root of the scanned repository.
To use it, name it in “Settings file”.
PT AI project
The job creates the project and the branch on the server when they are missing.
The project is named after the full path of the Deckhouse Code project with every / replaced by ::
group/subgroup/app writes to the group:subgroup:app project. A name longer than 255 characters is cut to 240,
and -p<PROJECT_ID> is appended, where <PROJECT_ID> is the project ID. The branch is named after the pipeline’s branch or tag.
The job writes the exact name to its log:
PT AI: scanning into project group:subgroup:app.PT AI project names are case-insensitive. Renaming or moving the project in Deckhouse Code changes its path: the next scan creates a new PT AI project, and the old one stays on the server with its history. To set up a security policy before the first scan, create the project in the PT AI web interface in advance, named by the same rule.
Every scan replaces the project’s settings on the server with the settings from the policy or the settings file, laid over the server’s default settings: modules, languages and language settings, the checkboxes of the “Scan” block and the whole black box. A change to these settings in the PT AI web interface lasts until the next scan. The job does not change the project’s security policy, the “Apply the security policy” checkbox, the project priority or the preferred agents: those are set in the PT AI web interface.
Scan queue
A PT AI agent on the server side does the scanning; the job waits for the result and holds the runner the whole time. The job’s duration is the wait in the server queue plus the scan itself, so give the project a job timeout with room to spare.
ptai_scan jobs of one branch of one project run one after another: the next one waits in the waiting_for_resource status,
holding no runner and spending no timeout. The branch pipeline and the merge request pipeline of that branch wait for each other.
If someone else is already scanning the branch, for example from the PT AI web interface, the job retries every 30 seconds
until the branch is free or the job timeout runs out.
A cancelled job, including one cancelled by a newer pipeline, stops its scan on the server. For only the latest commit to be scanned after several pushes in a row, turn on “Settings” → “CI/CD” → “General pipelines” → “Auto-cancel redundant pipelines” in the project. A job stopped by its timeout does not stop the scan: remove it from the queue in the PT AI web interface, on the Scan agents tab.
When the job fails
The PT AI scan has no findings threshold: every finding goes into the reports, and the job is failed by the project’s security policy on the PT AI server. After a finished scan, the job reads its verdict:
Rejected: the policy is broken, and the job fails with “the PT AI security policy rejected the scan”;Confirmed: the policy is met;None: the project’s policy check is off.
The server records the verdict a few seconds after the scan, so with the check on, the job waits for it for up to 120 seconds. A verdict that could not be fetched or read fails the job with “the PT AI security policy verdict could not be read”. The policy check is turned on and its rules are written in the PT AI web interface, in the project’s “Settings” → “Security policy”.
The job also fails when:
- the integration is missing or inactive, or has no address or token: “ERROR: the PT AI integration is missing or inactive: the job got no server address or token.”;
- the first call to the server fails: the job prints the aictl message and “Check the server address, the token and the certificate trust in the PT AI integration.”;
- the server refuses the scan settings: “ERROR: the PT AI server refused the settings aictl does not send: …” with the server’s response;
- the scan fails or no report arrives: “Failing job: the PT AI scan did not finish or produced no readable report.”; the job prints the reason the server gave after the line “PT AI: the server reports for this scan:”.
Reports
The job publishes the artifacts:
security-reports/gitlab/ptai.json: the SAST security report, PT AI’s report in the GitLab format, unchanged; its findings reach the vulnerability report;security-reports/junit/ptai.xml: the test report for the pipeline’s “Tests” tab;reports/ptai.jsonandreports/ptai.sarif: PT AI’s own JSON report and SARIF, as the server returned them.
On the “Tests” tab, every finding is a test. The suite is the PT AI module,
the test name is the finding type and place, for example Cross-Site Scripting [js/server.js:28];
a black box finding has the address in place of the location, a vulnerable component the component, version, CVEs and manifest.
The finding’s severity is the test’s severity property: Critical, High, Medium, Low or Info.
The test details hold the CWE and OWASP, the code and entry point, CVEs with their CVSS score, the current and recommended configuration value,
the malicious code calls, the black box address and exploit, whether the finding is new, and a link to the scan in the PT AI web interface.
When the PT AI security policy rejected the scan, a separate test with its verdict comes first.
The module, code, CVEs and black box address are in the test report only.
The reports are not masked: the exploit of a black box finding in reports/ptai.json and on the “Tests” tab holds the request line,
the Host header and the request body.
Troubleshooting
The scan does not appear in the pipeline
Check that:
- the PT AI integration is active for the project, or inherited from a group above it;
- the policy project is linked to the project or a group above it, and a policy rule matches the pipeline;
- the
ptaiaction of the policy names no integration setting and noFE_SECURITY_FAIL_ONthreshold.
“Test settings” or the first call to the server fails
Check the server URL, the token (no spaces or line breaks, not revoked, not expired, permission For the light agent and CI/CD plugins) and “Certificate trust”. “Test settings” shows the server’s response code, for example HTTP 401 for a wrong token.
The project is missing in PT AI
Look for the full project path with : in place of /. The job writes the exact name to its log in the line “PT AI: scanning into project …”.
“cannot downgrade 1.11 -> 1.10”
The file named in “Settings file” holds Version 1.11, and the server runs PT AI 6.0.
Set version 1.9 or 1.10 in the file.
No report after a repeated scan
The scan on the server is Done, but the job fails with “the PT AI scan did not finish or produced no readable report”
and prints the code REPORT_GENERATE_FAILED.
Run a full scan: change the scan settings in the policy, and the next run of the job scans the branch in full.