Environment variables security
Secured env variables
MegaLinter runs in a Docker image and calls the linters via the command line to gather their results.
If you run it from your CI/CD pipelines, the Docker image may have access to your environment variables, which can contain secrets defined in CI/CD variables.
As it can be complicated to fully trust the authors of all open-source linters, MegaLinter removes variables from the environment used to call linters.
Thanks to this feature, you only need to trust MegaLinter and its internal Python dependencies; there is no need to trust all the linters that are used.
You can add secured variables to the default list using the configuration property SECURED_ENV_VARIABLES in .mega-linter.yml or as an environment variable (priority is given to ENV variables over the .mega-linter.yml property).
Values can be:
- String (ex:
MY_SECRET_VAR) - Regular Expression (ex:
(MY.*VAR))
Environment variables are secured for each command line called (linters, plugins, SARIF formatter, etc.) except for PRE_COMMANDS, and only if you define secured_env: false in the command.
Secured configuration examples
- Example of adding extra secured variables in
.mega-linter.yml:
SECURED_ENV_VARIABLES:
- MY_SECRET_TOKEN
- ANOTHER_VAR_CONTAINING_SENSITIVE_DATA
- OX_API_KEY
- (MY.*VAR) # Regex format
- Example of adding extra secured variables in CI variables, so they cannot be overridden in
.mega-linter.yml:
SECURED_ENV_VARIABLES=MY_SECRET_TOKEN,ANOTHER_VAR_CONTAINING_SENSITIVE_DATA,OX_API_KEY
Default secured variables
If you override SECURED_ENV_VARIABLES_DEFAULT, it replaces the default list, so it's better to only define SECURED_ENV_VARIABLES to add items to the default list.
SECURED_ENV_VARIABLES_DEFAULT contains exact names and (regular expressions) matching patterns for commonly used sensitive environment variables:
- PAT
- SYSTEM_ACCESSTOKEN
- (^|)(USERNAME)($|)
- (^|)(PASSWORD|PASSWD|PASS|PWD)($|)
- (^|)(TOKEN|ID_TOKEN|ACCESS_TOKEN|REFRESH_TOKEN|BEARER)($|)
- (^|)(SECRET|SECRETS)($|)
- (^|)(API_KEY|APP_KEY|CLIENT_ID|CLIENT_SECRET|CLIENT_KEY|SECRET_KEY|ACCESS_KEY|ACCESS_KEY_ID|PRIVATE_KEY|SSH_KEY|SIGNING_KEY|ENCRYPTION_KEY|LICENSE_KEY)($|)
- (^|)(AUTH|AUTHORIZATION)($|)
- (^|)(CERT|CERTIFICATE|CA_BUNDLE|KUBECONFIG)($|)
- (^|)(CONNECTION_STRING|DATABASE_URL|DB_URL|DSN)($|)
- (GOOGLE_APPLICATION_CREDENTIALS)
- (GCP_SERVICE_ACCOUNT.*)
- (SFDX_CLIENT_ID_.*)
- (SFDX_CLIENT_KEY_.*)
- (^|)(SLACK|DISCORD|TEAMS|WEBHOOK)_URL($|)
This compact list is intentionally pattern-based: variables such as GITHUB_TOKEN, CI_JOB_TOKEN, NPM_TOKEN, GIT_AUTHORIZATION_BEARER, AWS_SECRET_ACCESS_KEY, AZURE_CLIENT_SECRET, OPENAI_API_KEY, DOCKER_PASSWORD, and SMTP_PASSWORD are hidden through these broader matchers.
Security boundaries and threat model
When a linter or plugin command is executed, MegaLinter builds a child-process environment where matched sensitive variables are replaced with HIDDEN_BY_MEGALINTER.
This means:
- The original value of a matched environment variable is not accessible from that environment variable entry in the child process.
This does not mean full sandboxing. A malicious dependency can still attempt to collect secrets from other channels, such as:
- Unmatched variables (for example after custom overrides of
SECURED_ENV_VARIABLES_DEFAULT) - Variables explicitly unhidden with
(linter-key)_UNSECURED_ENV_VARIABLES - Files mounted in the workspace, command arguments, or generated config files
- External credential sources (cloud metadata services, secret managers, network endpoints)
To maximize protection:
- Keep
SECURED_ENV_VARIABLES_DEFAULTunchanged when possible - Add your project-specific patterns with
SECURED_ENV_VARIABLES - Minimize extra credentials exposed to the MegaLinter runtime
Example (compromised dependency scenario):
- If a linter dependency (for example
axios) is compromised and executes malicious code, it can read the environment passed to that linter process. - In that environment, matched variables are already replaced by
HIDDEN_BY_MEGALINTER. - So reading
GITHUB_TOKEN,NPM_TOKEN,OPENAI_API_KEY, orAWS_SECRET_ACCESS_KEYfrom the process environment returnsHIDDEN_BY_MEGALINTER, not the original secret value. - The same attack could still try to obtain secrets from other channels listed above (files, arguments, external services, etc.).
Unhide variables for linters
You can configure exceptions for a specific linter by defining (linter-key)_UNSECURED_ENV_VARIABLES.
Variable names in this list won't be hidden from the linter commands.
TERRAFORM_TFLINT_UNSECURED_ENV_VARIABLES:
- GITHUB_TOKEN # Can contain string only, not regex