Environment Variable Rule

Environment Variable Rule Overview #

This rule validates environment variable names in GitHub Actions workflows to ensure they follow proper naming conventions. It detects invalid characters in variable names that would cause workflow failures or unexpected behavior.

Key Features: #

  • Invalid Character Detection: Identifies environment variable names containing &, =, or spaces
  • Multi-Level Validation: Checks environment variables at workflow, job, step, container, and service levels
  • Expression Handling: Properly handles environment variable names that contain GitHub Actions expressions

Security Impact #

Severity: Low (2/10)

Invalid environment variable names primarily cause operational issues, but can also have security implications:

  1. Workflow Failures: Variables with invalid characters will cause workflow parsing or runtime errors
  2. Injection Vectors: Improperly named variables might indicate injection attempts
  3. Configuration Errors: Typos in variable names can lead to misconfigured secrets or credentials
  4. Shell Interpretation Issues: Special characters can cause unexpected shell behavior

Understanding Environment Variables in GitHub Actions #

Environment variables can be defined at multiple levels in GitHub Actions:

# Workflow level
env:
  GLOBAL_VAR: "value"

jobs:
  build:
    # Job level
    env:
      JOB_VAR: "value"

    container:
      image: node:18
      # Container level
      env:
        CONTAINER_VAR: "value"

    services:
      postgres:
        image: postgres
        # Service level
        env:
          SERVICE_VAR: "value"

    steps:
      - name: Test
        # Step level
        env:
          STEP_VAR: "value"
        run: echo "$STEP_VAR"

Example Vulnerable Workflow #

Common environment variable naming issues:

name: CI Build

on: [push]

env:
  MY VAR: "value"        # ❌ Contains space
  DB=CONNECTION: "value" # ❌ Contains equals sign
  API&KEY: "secret"      # ❌ Contains ampersand

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      BUILD FLAG: "true"  # ❌ Contains space

    steps:
      - name: Test
        env:
          TEST&MODE: "unit"  # ❌ Contains ampersand
        run: echo "Testing"

What the Rule Detects #

1. Spaces in Variable Names #

Environment variable names cannot contain spaces:

env:
  MY VARIABLE: "value"  # ❌ Invalid: contains space

Error Output:

workflow.yml:5:3: Environment variable name '"MY VARIABLE"' is not formatted correctly. Please ensure that it does not include characters such as '&', '=', or spaces, as these are not allowed in variable names. [env-var]

2. Equals Signs in Variable Names #

Variable names cannot contain =:

env:
  DB=HOST: "localhost"  # ❌ Invalid: contains equals sign

Error Output:

workflow.yml:5:3: Environment variable name '"DB=HOST"' is not formatted correctly. Please ensure that it does not include characters such as '&', '=', or spaces, as these are not allowed in variable names. [env-var]

3. Ampersands in Variable Names #

Variable names cannot contain &:

env:
  USER&PASS: "secret"  # ❌ Invalid: contains ampersand

Error Output:

workflow.yml:5:3: Environment variable name '"USER&PASS"' is not formatted correctly. Please ensure that it does not include characters such as '&', '=', or spaces, as these are not allowed in variable names. [env-var]

Safe Patterns #

Pattern 1: Standard Naming Convention #

Use uppercase with underscores:

env:
  DATABASE_HOST: "localhost"
  DATABASE_PORT: "5432"
  API_KEY: ${{ secrets.API_KEY }}
  NODE_ENV: "production"

Pattern 2: Lowercase with Underscores #

Some projects prefer lowercase:

env:
  database_url: ${{ secrets.DATABASE_URL }}
  log_level: "debug"
  cache_enabled: "true"

Pattern 3: Dynamic Variable Names with Expressions #

When using expressions, the rule allows dynamic naming:

env:
  ${{ matrix.env_name }}: ${{ matrix.env_value }}

Pattern 4: Container and Service Environment Variables #

jobs:
  test:
    runs-on: ubuntu-latest

    container:
      image: node:18
      env:
        NODE_OPTIONS: "--max-old-space-size=4096"

    services:
      postgres:
        image: postgres:14
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: test_db

Technical Detection Mechanism #

The rule checks environment variable names at multiple levels:

func (checker *EnvironmentVariableChecker) validateEnvironmentVariables(env *ast.Env) {
    if env == nil || env.Expression != nil {
        return
    }
    for _, variable := range env.Vars {
        if variable.Name.ContainsExpression() {
            continue // Variable names can contain expressions (#312)
        }
        if strings.ContainsAny(variable.Name.Value, "&= ") {
            checker.Errorf(
                variable.Name.Pos,
                "Environment variable name '%q' is not formatted correctly...",
                variable.Name.Value,
            )
        }
    }
}

Validation Scope #

The rule validates environment variables at all levels:

LevelYAML PathExample
Workflowenv:Top-level environment variables
Jobjobs.<job_id>.env:Job-specific variables
Stepjobs.<job_id>.steps[*].env:Step-specific variables
Containerjobs.<job_id>.container.env:Container environment
Servicejobs.<job_id>.services.<service_id>.env:Service environment

Best Practices #

1. Use Standard Naming Conventions #

Follow Unix/POSIX conventions for environment variable names:

# Good: SCREAMING_SNAKE_CASE
env:
  DATABASE_URL: ${{ secrets.DATABASE_URL }}
  API_ENDPOINT: "https://api.example.com"
  MAX_RETRY_COUNT: "3"

# Also acceptable: lowercase_snake_case
env:
  database_url: ${{ secrets.DATABASE_URL }}

2. Avoid Special Characters #

Only use alphanumeric characters and underscores:

# Good
env:
  MY_VAR_123: "value"
  _INTERNAL_VAR: "value"

# Bad
env:
  MY-VAR: "value"    # Hyphens not recommended (works but unusual)
  MY.VAR: "value"    # Periods may cause issues

3. Use Meaningful Names #

Variable names should be descriptive:

# Good: Descriptive names
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  NPM_REGISTRY_URL: "https://registry.npmjs.org"
  BUILD_ARTIFACT_PATH: "./dist"

# Bad: Vague names
env:
  VAR1: "value"
  X: "something"

Organize environment variables logically:

env:
  # Database configuration
  DB_HOST: "localhost"
  DB_PORT: "5432"
  DB_NAME: "myapp"

  # API configuration
  API_URL: "https://api.example.com"
  API_TIMEOUT: "30"

Common Mistakes #

Mistake 1: Copy-Paste Errors #

# ❌ Wrong: Accidentally included shell syntax
env:
  export MY_VAR: "value"  # 'export' is shell syntax, not YAML

# ✅ Correct
env:
  MY_VAR: "value"

Mistake 2: Confusing Key-Value Syntax #

# ❌ Wrong: Equals sign in name
env:
  MY_VAR=value:  # Incorrect syntax

# ✅ Correct
env:
  MY_VAR: "value"

Mistake 3: Quotes in Variable Names #

# ❌ Wrong: Quotes are part of the name
env:
  "MY_VAR": "value"  # Quotes become part of the name in some parsers

# ✅ Correct
env:
  MY_VAR: "value"

Relationship to Other Rules #

Detection Example #

Running sisakulint on a workflow with invalid environment variable names:

$ sisakulint .github/workflows/ci.yml

.github/workflows/ci.yml:5:3: Environment variable name '"MY VAR"' is not formatted correctly. Please ensure that it does not include characters such as '&', '=', or spaces, as these are not allowed in variable names. [env-var]
     5 👈|  MY VAR: "value"

.github/workflows/ci.yml:6:3: Environment variable name '"DB=HOST"' is not formatted correctly. Please ensure that it does not include characters such as '&', '=', or spaces, as these are not allowed in variable names. [env-var]
     6 👈|  DB=HOST: "localhost"

.github/workflows/ci.yml:7:3: Environment variable name '"API&KEY"' is not formatted correctly. Please ensure that it does not include characters such as '&', '=', or spaces, as these are not allowed in variable names. [env-var]
     7 👈|  API&KEY: "secret"

References #

Testing #

To test this rule:

# Detect invalid environment variable names
sisakulint .github/workflows/*.yml

Configuration #

This rule is enabled by default. To disable it:

sisakulint -ignore env-var

Disabling this rule is not recommended as invalid environment variable names will cause workflow failures or unexpected behavior.