How do I migrate from hardcoded secrets to secure patterns in EK9?

← Security and Sanitization · Ref: Q705

When the EK9 compiler detects a hardcoded secret (E11080-E11086), follow this migration pattern:

STEP 1: IDENTIFY THE SECRET TYPE

The error code tells you what was detected:

  E11080 → Cloud provider key (AWS, GCP, Azure)
  E11081 → Platform token (GitHub, GitLab, Slack)
  E11082 → Private key material (RSA, ECDSA, OpenSSH)
  E11083 → Database URL with password
  E11084 → JWT token
  E11086 → API key (Stripe, OpenAI, etc.)

STEP 2: CHOOSE AN ENVIRONMENT VARIABLE NAME

Use a descriptive, uppercase name with underscores:

  AWS_ACCESS_KEY_ID, STRIPE_SECRET_KEY, DB_PASSWORD

STEP 3: REPLACE WITH SENSITIVEGET

  BEFORE: key <- "AKIAIOSFODNN7EXAMPLE1"
  AFTER:  env <- EnvVars()
          key <- env.sensitiveGet("AWS_ACCESS_KEY_ID")

STEP 4: ADD GUARD FOR MISSING VALUES

  if key <- env.sensitiveGet("AWS_ACCESS_KEY_ID")
    configureAws(key)
  else
    stderr.println("AWS_ACCESS_KEY_ID not set")

STEP 5: SET ENVIRONMENT VARIABLE

  export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE1
  Or use your platform's secrets management.

DATABASE URL MIGRATION

  BEFORE: url <- "postgres://admin:pass@host/db"
  AFTER:  url <- env.sensitiveGet("DATABASE_URL")

JWT TOKEN MIGRATION

  BEFORE: token <- "eyJhbGci..."
  AFTER:  token <- env.sensitiveGet("AUTH_TOKEN")
  Or generate tokens dynamically at runtime.

See Q701 for Sensitive type. See Q702 for sensitiveGet(). See Q704 for detection details.

Example

defines module qa.security.credentialmigration

  defines function

    <?-
      Correct pattern: cloud provider credential migration.
    -?>
    testCloudCredentialMigration()
      stdout <- Stdout()
      stderr <- Stderr()
      env <- EnvVars()

      //AFTER: Load from environment variable
      if awsKey <- env.sensitiveGet("AWS_ACCESS_KEY_ID")
        stdout.println("AWS key loaded: " + awsKey)
      else
        stderr.println("Set AWS_ACCESS_KEY_ID environment variable")

    <?-
      Correct pattern: API key migration.
    -?>
    testApiKeyMigration()
      stdout <- Stdout()
      stderr <- Stderr()
      env <- EnvVars()

      //AFTER: Load from environment variable
      if stripeKey <- env.sensitiveGet("STRIPE_SECRET_KEY")
        stdout.println("Stripe key loaded: " + stripeKey)
      else
        stderr.println("Set STRIPE_SECRET_KEY environment variable")

    <?-
      Correct pattern: database URL migration.
    -?>
    testDatabaseUrlMigration()
      stdout <- Stdout()
      stderr <- Stderr()
      env <- EnvVars()

      //AFTER: Separate configuration from secrets
      dbHost <- env.get("DB_HOST")
      dbName <- env.get("DB_NAME")
      dbPassword <- env.sensitiveGet("DB_PASSWORD")

      if dbHost? and dbName? and dbPassword?
        stdout.println("Database configured with separate components")
      else
        stderr.println("Configure DB_HOST, DB_NAME, and DB_PASSWORD")

    <?-
      Correct pattern: JWT token migration (generate at runtime).
    -?>
    testJwtTokenMigration()
      stdout <- Stdout()
      stderr <- Stderr()
      env <- EnvVars()

      //For test tokens: load from environment
      if testToken <- env.sensitiveGet("TEST_JWT_TOKEN")
        stdout.println("Test JWT loaded: " + testToken)
      else
        stderr.println("Set TEST_JWT_TOKEN for testing")

    <?-
      Correct pattern: private key migration.
    -?>
    testPrivateKeyMigration()
      stdout <- Stdout()
      stderr <- Stderr()
      env <- EnvVars()

      //AFTER: Load key path or content from environment
      if keyPath <- env.get("TLS_KEY_PATH")
        stdout.println("TLS key path: " + keyPath)
      else
        stderr.println("Set TLS_KEY_PATH environment variable")

  defines program

    CredentialMigrationDemo()
      stdout <- Stdout()
      stdout.println("Credential migration demonstrations")
      testCloudCredentialMigration()
      testApiKeyMigration()
      testDatabaseUrlMigration()
      testJwtTokenMigration()
      testPrivateKeyMigration()

Common mistakes

E08090 — AWS access keys are detected at compile time. Extract the key to an environment variable and load with sensitiveGet(). See ek9 -h E08090 for details.

Incorrect:

awsKey <- "AKIAIOSFODNN7EXAMPLE1"

Correct:

awsKey <- env.sensitiveGet("AWS_ACCESS_KEY_ID")

E08090 — Stripe API keys with the 'sk_test_' prefix are detected at compile time. Load API keys from environment variables using sensitiveGet(). See ek9 -h E08090 for details.

Incorrect:

stripeKey <- "sk_test_abcdefghijklmnopqrstuvwxyz"

Correct:

stripeKey <- env.sensitiveGet("STRIPE_SECRET_KEY")

E08090 — GitHub personal access tokens with the 'ghp_' prefix are detected at compile time. Store platform tokens in environment variables. See ek9 -h E08090 for details.

Incorrect:

testToken <- "ghp_ABCDEFabcdef1234567890abcdef12345678"

Correct:

testToken <- env.sensitiveGet("TEST_JWT_TOKEN")

E11083 — Database URLs with embedded passwords are detected at compile time. Store the connection URL in an environment variable. See ek9 -h E11083 for details.

Incorrect:

dbPassword <- "postgres://admin:s3cret@db.example.com/prod"

Correct:

dbPassword <- env.sensitiveGet("DB_PASSWORD")

E08090 — EC private key material is detected at compile time. Load private keys from files or environment variables at runtime. See ek9 -h E08090 for details.

Incorrect:

keyPath <- "-----BEGIN EC PRIVATE KEY-----"

Correct:

keyPath <- env.get("TLS_KEY_PATH")
Other ways to ask this
  • How do I fix hardcoded credential errors in EK9?
  • What is the EK9 pattern for replacing inline secrets?
  • How do I move from hardcoded passwords to environment variables in EK9?

Coming from another language?

Java: Secrets are typically moved from source to properties files (still in repo), then to environment variables, then to Vault/AWS Secrets Manager. Multiple migration steps. Python: Similar journey from .env files to proper secrets management. EK9: The compiler forces the first migration step (source → environment variable) automatically. No optional intermediate steps.

Keywords: connect, refactor, fix, secret, database, credential, service, url, environment, hardcoded, detection, error, migrate, replace, password, driver, pattern