Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset golang/GO-SEC-004 --project .About This Rule
Understanding the vulnerability and how it is detected
Hardcoded credentials are secrets — passwords, API keys, tokens, signing keys, and connection strings — embedded directly as string literals in source code. This is one of the most frequently occurring and impactful security vulnerabilities in software development, consistently appearing in real breaches with catastrophic consequences.
**Why hardcoded secrets are permanently dangerous**:
Source code is copied, forked, backed up, and diffed far more broadly than developers realize. A secret committed to any version control system persists in the commit history indefinitely — even `git rm` and `git commit` do not remove it. An attacker with read access to any historical snapshot (via GitHub, GitLab, Bitbucket, backup, or zip export) recovers the credential. Forcing a secret into git history is effectively publishing it.
**Surface area of secret exposure beyond git**: - "**Compiled Go binaries**: Go embeds string literals directly in the binary's `.rodata`" section. The Unix `strings` command extracts all printable strings of 4+ characters. Tools like Ghidra with the "ghostrings" plugin specifically hunt for string constants that look like credentials. A hardcoded JWT secret or database password survives unchanged in every compiled artifact shipped to customers or placed in container images. - "**Container image layers**: Docker layers are union filesystem snapshots. Each layer" is a tar archive. `docker history --no-trunc` and `docker inspect` expose build-time ARG values. If a binary containing hardcoded credentials is in the image, `docker save` followed by `tar xf` and `strings` extracts them. - "**CI/CD pipeline artifacts**: Build systems cache compiled binaries and run logs. A" test output that prints a hardcoded constant, or a build artifact in a public artifact store, exposes the credential to anyone with artifact access. - "**Log files and crash dumps**: Go programs that log their configuration at startup" (common in 12-factor app patterns) may log environment variables or struct fields — including credential-named fields initialized from string literals.
**Real-world incidents involving hardcoded credentials**:
*Toyota T-Connect breach (2022–2023)*: Toyota disclosed that a contractor had accidentally published source code to a public GitHub repository containing credentials for a data server. The exposed data server contained information of approximately 296,019 Toyota T-Connect customers — names, phone numbers, and vehicle identification numbers. The credentials remained valid and exposed for approximately 4 years and 9 months before discovery. Toyota stated no financial data was accessed but could not rule out third-party access during the exposure window.
*Internet Archive breach (October 2024)*: Threat actors obtained a GitLab personal access token that was exposed in a public repository. Using this token, they accessed the Internet Archive's GitLab instance and exfiltrated configuration files. The breach exposed 31 million user records (email addresses, usernames, bcrypt-hashed passwords, and other internal data). The token, once hardcoded in the repository, became the entry point for the entire breach.
*Slack GitHub repository credential exposure (2022)*: Slack disclosed that hashed employee credentials and GitHub repository cloning tokens were exposed when an attacker gained access to a subset of Slack's GitHub repositories. The exposure included tokens that could be used to access Slack's internal systems. While Slack rotated all affected credentials immediately, the incident demonstrated how a single exposed token creates a lateral movement path from external repository access to internal infrastructure.
**Scale of the problem — GitGuardian research (2024)**: GitGuardian's "State of Secrets Sprawl" report analyzed over 1 billion commits: - 23.8 million new plaintext secrets were detected in public GitHub repositories in 2023 - 70% of secrets exposed in 2021 remain valid and active 2 years later — secret rotation after discovery is the exception, not the rule - "The most common secret types: API keys (35%), generic credentials (28%), private keys (17%)" - "Developer-to-secret ratio: approximately 1 hardcoded secret per 1,000 commits in" enterprise repositories
**Extraction techniques attackers use**: 1. `strings /path/to/binary | grep -iE "(password|secret|key|token)" | grep -v "^[[:space:]]*$"` 2. TruffleHog v3: `trufflehog git file:///path/to/repo --only-verified` — scans git history with entropy analysis and regex patterns against known-secret formats 3. Gitleaks: `gitleaks detect --source /path/to/repo` — rule-based scanning with 150+ built-in patterns for AWS keys, GitHub tokens, Stripe keys, etc. 4. Docker layer inspection: `docker save image:tag | tar xf - | find . -name "*.tar" -exec tar xf {} \; | strings | grep -i secret` 5. Ghidra ghostrings plugin: static analysis of Go binaries to identify Go string constants and cross-reference them against credential patterns
**CWE taxonomy for this vulnerability class**: - "**CWE-798** (parent): General hardcoded credentials — covers any credential type" - "**CWE-259** (child): Specifically hardcoded passwords in authentication code" - "**CWE-321** (child): Hardcoded cryptographic keys — JWT signing secrets, AES keys," HMAC secrets. These are both a credential and a cryptographic failure simultaneously.
**Go-specific remediation hierarchy** (in order of increasing security): 1. `os.Getenv("SECRET_NAME")` — environment variables; acceptable for development, simple deployments. Note: env vars are visible in `/proc/<pid>/environ`, `docker inspect`, and CI/CD log output if logged. 2. `github.com/spf13/viper` with config files excluded from git — supports env var binding, remote config (etcd, Consul), and layered config. Better than bare os.Getenv for complex apps. 3. `github.com/hashicorp/vault/sdk` — HashiCorp Vault dynamic secrets. Vault generates short-lived credentials on demand and revokes them automatically. Compromised credentials expire without requiring rotation. Vault audit logs all secret accesses. 4. AWS Secrets Manager (`github.com/aws/aws-sdk-go-v2/service/secretsmanager`) / GCP Secret Manager / Azure Key Vault — cloud-native secrets management with IAM-based access control, automatic rotation for supported services (RDS, Redshift), and CloudTrail audit logging.
**CISA Secure by Design guidance**: CISA's "Secure by Design" principles explicitly list elimination of default and hardcoded credentials as a foundational requirement. The guidance states that software manufacturers should make it technically impossible to deploy software with default credentials by requiring credential configuration as part of the installation process.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Permanent Exposure via Git History
Any secret committed to version control persists indefinitely in git history. Even `git rm` + `git push` leaves the secret in every historical clone, CI/CD artifact, and backup. Tools like TruffleHog and Gitleaks scan all commits, not just the current HEAD. The only remediation is credential rotation — the history cannot be practically sanitized once other parties have cloned the repository.
Binary Reverse Engineering
Go embeds string literals verbatim in compiled binaries. A database password or API key in a Go string constant appears in the binary's .rodata section readable by the `strings` command without any disassembly. Compiled binaries distributed to customers, deployed in container images, or included in GitHub releases expose credentials to anyone who downloads them.
Supply Chain Compromise
An attacker who compromises a developer's workstation, a CI/CD pipeline, or a source code repository recovers all hardcoded credentials with a single search. This provides immediate access to every environment — development, staging, and production — where those credentials are used. Hardcoded credentials make a single point of compromise (developer laptop) equivalent to full infrastructure compromise.
Credential Reuse Across Environments
Hardcoded credentials typically use the same value across all environments. When a staging environment credential is exposed, it often also works in production because developers hardcoded the same value in both. Per-environment rotation is only possible with externalized configuration.
How to Fix
Recommended remediation steps
- 1Use os.Getenv() as a minimum for all credential values — never hardcode string literals.
- 2Validate that required secrets are present at startup; fail fast with a clear error message.
- 3Use HashiCorp Vault or AWS/GCP/Azure Secrets Manager for production workloads.
- 4Add .env and config files containing secrets to .gitignore before initial commit.
- 5Run TruffleHog or Gitleaks as a pre-commit hook and in CI to catch secrets before push.
- 6If a credential is ever committed, rotate it immediately — assume it is compromised.
- 7Use per-environment secrets — staging and production must never share credentials.
- 8Store JWT signing keys with minimum 256-bit entropy (32 random bytes from crypto/rand).
- 9Audit binary artifacts for embedded credentials using `strings binary | grep -iE 'password|secret|key|token'`.
- 10Follow the principle of least privilege — each service should have its own credentials with minimal scope.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
Variable name pattern matching for password/secret/api_key/apikey/token/credential/passwd patterns. Produces findings on any variable with these name patterns used in function calls. Requires manual review to confirm whether the assigned value is a hardcoded literal vs a runtime value — the rule flags the variable name as a strong signal warranting review.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Go
SQL Injection via database/sql
User-controlled input reaches database/sql query methods without parameterization, enabling SQL injection — ranked
JWT Parsed Without Signature Verification
jwt.ParseUnverified() skips signature validation entirely — any attacker can forge arbitrary JWT claims (sub, role, admin) without knowing the signing key.
Frequently Asked Questions
Common questions about Hardcoded Credentials in Source Code
New feature
Get these findings posted directly on your GitHub pull requests
The Hardcoded Credentials in Source Code rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.