SC005: NoHardcodedSecretsV2
Overview
| Property | Value |
|---|---|
| ID | SC005 |
| Name | NoHardcodedSecretsV2 |
| Group | security |
| Severity | ERROR |
Description
Enhanced AST-based secret detection that analyzes Python source code structure to identify hardcoded secrets with higher accuracy and fewer false positives than regex-based scanning.
This advanced check uses Abstract Syntax Tree (AST) analysis to:
- Understand code context (assignments, function calls, class attributes)
- Detect secrets in string literals, f-strings, and concatenations
- Identify secrets passed to functions, APIs, and configurations
- Reduce false positives by analyzing variable names and usage patterns
What it checks
AST-based detection patterns
The check analyzes the code structure for:
Variable assignments
# Detected: assignment to secret-named variable
api_key = "sk-1234567890abcdef"
AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG"
database_password = "super_secret_123"Dictionary literals
# Detected: secrets in config dictionaries
config = {
"api_key": "sk-1234567890abcdef",
"password": "hardcoded_password",
}Function call arguments
# Detected: secrets passed to functions
client = OpenAI(api_key="sk-1234567890abcdef")
connect(password="database_password")Class attributes
# Detected: secrets in class definitions
class Config:
SECRET_KEY = "my-secret-key-12345"
API_TOKEN = "ghp_xxxxxxxxxxxx"F-strings and concatenation
# Detected: secrets constructed via f-strings
auth_header = f"Bearer sk-{secret_part}"
full_key = "AKIA" + "1234567890ABCDEF"Secret patterns detected
| Pattern | Description |
|---|---|
sk-... |
OpenAI API keys |
AKIA... |
AWS Access Key IDs |
ghp_*, gho_*, ghs_* |
GitHub tokens |
xox[baprs]-* |
Slack tokens |
-----BEGIN * PRIVATE KEY----- |
Private keys |
| High-entropy strings | Generic secrets (configurable) |
Result states
- PASSED: No hardcoded secrets found
- FAILED: Secrets detected with file, line, and context
- SKIPPED: Unable to parse Python files
How to fix
Use environment variables
import os
# Bad: hardcoded
API_KEY = "sk-1234567890abcdef"
# Good: from environment
API_KEY = os.environ["API_KEY"]
# or with default
API_KEY = os.environ.get("API_KEY", "")Use python-dotenv
from dotenv import load_dotenv
import os
load_dotenv() # Load from .env file
API_KEY = os.environ.get("API_KEY")
DATABASE_URL = os.environ.get("DATABASE_URL")Create a .env file (never commit to git):
# .env
API_KEY=sk-1234567890abcdef
DATABASE_URL=postgresql://user:pass@localhost/dbUse a secrets manager
# AWS Secrets Manager
import boto3
client = boto3.client('secretsmanager')
secret = client.get_secret_value(SecretId='my-secret')
# HashiCorp Vault
import hvac
client = hvac.Client(url='https://vault.example.com')
secret = client.secrets.kv.read_secret_version(path='my-secret')Use pydantic-settings
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
api_key: str
database_url: str
class Config:
env_file = ".env"
settings = Settings() # Loads from environment/.envProtect your .gitignore
# Secrets and credentials
.env
.env.*
*.pem
*.key
secrets.toml
credentials.json
Comparison with SC001
| Feature | SC001 (NoHardcodedSecrets) | SC005 (NoHardcodedSecretsV2) |
|---|---|---|
| Detection method | Regex patterns | AST analysis |
| Context awareness | Limited | Full code structure |
| False positive rate | Higher | Lower |
| f-string detection | Basic | Full support |
| Dictionary detection | Limited | Full support |
| Performance | Faster | Slightly slower |
Why ERROR severity?
This check is an ERROR because:
- Hardcoded secrets are critical security vulnerabilities
- Once committed, secrets persist in git history
- AST analysis provides high-confidence detections
- False positives are minimized, so findings should be addressed
Configuration
Skip this check
[tool.pycmdcheck]
skip = ["SC005"]CLI
pycmdcheck --skip SC005Skip entire security group
pycmdcheck --skip-group security