Description
Embedding credentials such as usernames, passwords, or API keys directly in source code exposes them if the code is disclosed.
Potential impact
- Credential exposure: An attacker may use leaked credentials for unauthorized access.
- Privilege abuse: Credentials with administrator privileges can allow an attacker to modify the system.
- Data disclosure: Sensitive information may be exposed.
Remediation
- Supply credentials through environment variables instead of embedding them in code.
- Store and manage credentials in a protected secret store.
- Rotate credentials as needed and revoke unused credentials.
Revoke exposed credentials and replace them with new values. In the examples, set DATABASE_URL to the complete connection string managed by your deployment environment.
Examples
Django
Before
python
# Hardcoded Django credentials
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'myuser',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '5432',
}
}
After
python
# Django credentials from the environment
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}
Explanation:
- Before: Database credentials are embedded in the source and may be disclosed with it.
- After: Credentials are supplied through the environment instead of the source.
Flask
Before
python
# Hardcoded Flask credentials
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://myuser:mypassword@localhost/mydatabase'
After
python
# Flask credentials from the environment
import os
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
Explanation:
- Before: The database connection string embeds credentials.
- After: The complete connection string comes from the environment.
FastAPI
Before
python
# Hardcoded FastAPI credentials
DATABASE_URL = "postgresql://myuser:mypassword@localhost/mydatabase"
@app.on_event("startup")
async def startup():
app.state.pool = await asyncpg.create_pool(DATABASE_URL)
After
python
# FastAPI credentials from the environment
import os
DATABASE_URL = os.environ['DATABASE_URL']
@app.on_event("startup")
async def startup():
app.state.pool = await asyncpg.create_pool(DATABASE_URL)
Explanation:
- Before: The database connection string embeds credentials.
- After: The complete connection string comes from the environment.