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