How Hardcoded AWS Credentials Happen in Node.js Configuration Files and How to Fix It
Introduction
In the S3 Express deployment configuration file (deployments/s3_express/settings.s3express.example), security scanning revealed a critical hardcoded AWS Secret Access Key at line 3. The file contained a literal placeholder secret: AWS_SECRET_ACCESS_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa. While this was intended as an example file, this pattern creates a dangerous exploit primitive—a code structure that automated attack tools could leverage to extract credentials if the file were accidentally deployed, committed without sanitization, or included in documentation.
This vulnerability matters because example configuration files often become templates for production deployments. Developers copying this file might accidentally commit the example credentials to version control, where they become discoverable through git history, GitHub search, or security scanning tools. Even worse, if this repository is public or the file is included in package distributions, attackers can directly harvest the credentials.
The Vulnerability Explained
Hardcoded credentials are authentication secrets (API keys, passwords, tokens) embedded directly in application code or configuration files rather than loaded from secure external sources at runtime.
The Vulnerable Code
// deployments/s3_express/settings.s3express.example (BEFORE FIX)
S3_BUCKET_NAME=my-bucket-name--usw2-az1--x-s3
AWS_ACCESS_KEY_ID=ZZZZZZZZZZZZZZZZZZZZ
AWS_SECRET_ACCESS_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
AWS_SESSION_TOKEN=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
S3_SERVER=s3express-usw2-az1.us-west-2.amazonaws.com
S3_SERVER_PORT=443
The problem is on line 3: AWS_SECRET_ACCESS_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
This line contains a literal 40-character string that follows the AWS Secret Access Key format exactly. While the specific characters are fake, the pattern itself is a credential template that:
- Trains automated exploit tools - Security tools and exploit frameworks recognize this pattern as a valid AWS credential structure
- Creates a copy-paste risk - Developers may copy this file and forget to replace the placeholder before committing to version control
- Appears in search results - Public repositories with this pattern are discoverable via GitHub search or security scanning services
- Persists in git history - Even if deleted later, the credentials remain in git history unless the entire commit is purged
Attack Scenario
An attacker could exploit this vulnerability through several pathways:
-
Public Repository Discovery: The attacker finds this repository on GitHub and searches for AWS credential patterns. They discover the
settings.s3express.examplefile in the public history. -
Credential Extraction: Even though these specific characters are fake, the attacker now has a template for what valid AWS credentials look like in this codebase. If a developer ever accidentally commits real credentials using this same file as a template, the attacker can identify and extract them.
-
Supply Chain Attack: If this package is published to npm, the attacker could analyze the distributed package contents, looking for any credential patterns. The example file's presence suggests the developers work with AWS, making targeted social engineering or supply chain attacks more likely.
-
Automated Scanning: Tools like GitGuardian, TruffleHog, or custom scanners automatically flag this file as containing credential patterns. If the real credentials follow the same structure, they'll be caught in the same scan.
Real-world impact: A developer working with this library copies settings.s3express.example to settings.s3express, then accidentally commits it with real AWS credentials to a private repository. An attacker with access to that repository (through a compromised account, leaked credentials, or social engineering) can now access the S3 bucket, exfiltrate data, or modify objects. AWS charges could spike dramatically if the attacker uses the credentials to perform large-scale operations.
The Fix
The security fix removes the credential template by replacing the literal secret with a generic, clearly descriptive placeholder:
S3_BUCKET_NAME=my-bucket-name--usw2-az1--x-s3
AWS_ACCESS_KEY_ID=ZZZZZZZZZZZZZZZZZZZZ
-AWS_SECRET_ACCESS_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+AWS_SECRET_ACCESS_KEY=<YOUR_AWS_SECRET_ACCESS_KEY>
AWS_SESSION_TOKEN=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
S3_SERVER=s3express-usw2-az1.us-west-2.amazonaws.com
S3_SERVER_PORT=443
What changed: Line 3 now contains <YOUR_AWS_SECRET_ACCESS_KEY> instead of the 40-character placeholder.
Why this matters:
- Breaks the credential template - The new placeholder is clearly not a valid AWS secret format. Automated scanning tools won't flag it as a credential.
- Explicit instruction - The angle-bracket syntax
<YOUR_...>is a universal convention for "replace this with your own value." Developers immediately understand they need to substitute their actual credentials. - Removes the exploit primitive - Even if a developer copies this file without modification, they'll get an obviously invalid credential (
<YOUR_AWS_SECRET_ACCESS_KEY>) that will fail immediately when used, rather than a pattern that could be mistaken for a real credential. - Maintains usability - The fix doesn't change the file's functionality. Developers still use it as a template; they just can't accidentally use it as-is.
This is a defensive hardening change—it doesn't fix a currently exploitable vulnerability, but it removes a code pattern that could be chained with other weaknesses (like accidental commits to public repositories) by increasingly capable automated attack tools.
Prevention & Best Practices
1. Never Hardcode Credentials in Configuration Files
Use environment variables or secrets management systems instead:
// GOOD: Load from environment
const accessKeyId = process.env.AWS_ACCESS_KEY_ID;
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
// BETTER: Use AWS SDK credential chain (automatic IMDS/role detection)
const s3Client = new S3Client({
// Credentials loaded automatically from EC2 role, environment, or ~/.aws/credentials
});
2. Use Placeholder Syntax in Example Files
Example and template files should use clear, unmistakable placeholders:
# GOOD: Obvious placeholders that can't be confused with real credentials
AWS_ACCESS_KEY_ID=<YOUR_AWS_ACCESS_KEY_ID>
AWS_SECRET_ACCESS_KEY=<YOUR_AWS_SECRET_ACCESS_KEY>
AWS_SESSION_TOKEN=<YOUR_AWS_SESSION_TOKEN>
# BAD: Looks like real credentials
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
3. Implement Pre-commit Hooks
Use tools to prevent credential commits before they reach version control:
# Install git-secrets to scan for credential patterns
brew install git-secrets
git secrets --install
git secrets --register-aws
# Now git will reject commits containing AWS credentials
4. Scan Existing Repositories
Check if credentials were already committed:
# Scan with TruffleHog
pip install truffleHog
truffleHog filesystem . --only-verified
# Scan with GitGuardian
pip install gitguardian-cli
ggshield secret scan path .
5. Use .gitignore for Sensitive Files
# .gitignore
settings.s3express
.env
.env.local
aws_credentials
Important: .gitignore only prevents future commits. If credentials were already committed, use git filter-branch or BFG Repo-Cleaner to remove them from history.
6. Rotate Credentials Immediately
If credentials were ever exposed:
# In AWS Console: Create new access keys
# Delete the exposed key
# Update all references to use the new key
Security Standards & References
This vulnerability aligns with:
- CWE-798: Use of Hard-Coded Credentials
- OWASP Top 10 2021 - A07:2021: Identification and Authentication Failures
- OWASP Top 10 2024 - A01:2025: Broken Access Control (credential exposure)
Key Takeaways
-
Example files are templates, not safe defaults - The
settings.s3express.examplefile was intended as a template, but using realistic-looking credentials trained developers to accept that pattern as normal, increasing the risk of accidental exposure. -
Credential patterns are discoverable - AWS Secret Access Keys have a recognizable format (40 characters, specific character set). Automated scanning tools and attackers use pattern matching to find them in public repositories and git history.
-
Placeholder syntax prevents confusion - Using
<YOUR_AWS_SECRET_ACCESS_KEY>instead of literal characters makes it immediately obvious that substitution is required, reducing copy-paste errors. -
Pre-commit scanning catches mistakes - Tools like
git-secretsandtruffleHogcan automatically reject commits containing credential patterns, preventing accidental exposure before code reaches version control. -
Defensive hardening removes exploit primitives - Even when a vulnerability isn't currently exploitable, removing patterns that automated tools could chain with other weaknesses raises the overall security bar.
How Orbis AppSec Detected This
Source: The hardcoded credential pattern in the configuration file template (settings.s3express.example), detected by static analysis scanning for AWS credential formats.
Sink: Line 3 of deployments/s3_express/settings.s3express.example where the AWS Secret Access Key is assigned a literal 40-character string matching AWS credential patterns.
Missing control: No validation to ensure placeholder values are used in example files. No enforcement that example files contain only obviously-fake credentials that cannot be mistaken for real ones.
CWE: CWE-798 (Use of Hard-Coded Credentials) - The application contains hard-coded credentials that could be discovered through source code analysis or repository history.
Fix: Replaced the literal 40-character credential placeholder with a descriptive placeholder string <YOUR_AWS_SECRET_ACCESS_KEY> that is clearly not a valid AWS credential format and follows standard template conventions.
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
Hardcoded credentials in example configuration files represent a subtle but critical security risk. While the specific credentials in settings.s3express.example were intentionally fake, the pattern they followed created an exploit primitive that automated tools could leverage if real credentials were ever accidentally committed using this file as a template.
The fix—replacing literal credential placeholders with descriptive angle-bracket syntax—is a simple but effective defensive hardening measure. It removes the template pattern that developers might unconsciously accept as "normal," reducing the cognitive load required to recognize that substitution is necessary.
For developers working with AWS credentials in Node.js applications, the key lesson is: never use realistic-looking placeholders in example files. Use environment variables or secrets management systems for actual credentials, implement pre-commit hooks to catch mistakes, and scan existing repositories for any credentials that may have already been exposed.
By combining these practices with proactive static analysis scanning (like Semgrep's detected-aws-secret-access-key rule), you can significantly reduce the risk of credential leakage in your applications and dependencies.
References
- CWE-798: Use of Hard-Coded Credentials
- OWASP: Secrets Management Cheat Sheet
- AWS: Best Practices for Managing AWS Access Keys
- Semgrep: Detected AWS Secret Access Key Rule
- git-secrets: Prevents you from committing secrets
- TruffleHog: Find secrets in your codebase
- GitHub PR: harden: aws secret access key detected in settings.s3express.example...