fix(security): block AWS SDK creds from subprocess env
This commit is contained in:
@ -93,6 +93,26 @@ class TestProviderEnvBlocklist:
|
||||
for var in registry_vars:
|
||||
assert var not in result_env, f"{var} leaked into subprocess env"
|
||||
|
||||
def test_aws_sdk_provider_vars_are_stripped(self):
|
||||
"""AWS SDK credential-chain vars must not leak to subprocesses."""
|
||||
aws_vars = {
|
||||
"AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
|
||||
"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"AWS_SESSION_TOKEN": "session-token",
|
||||
"AWS_PROFILE": "production",
|
||||
"AWS_SHARED_CREDENTIALS_FILE": "/home/user/.aws/credentials",
|
||||
"AWS_CONFIG_FILE": "/home/user/.aws/config",
|
||||
"AWS_WEB_IDENTITY_TOKEN_FILE": "/var/run/secrets/token",
|
||||
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI": "/v2/credentials/123",
|
||||
"AWS_CONTAINER_CREDENTIALS_FULL_URI": "http://169.254.170.2/v2/credentials/123",
|
||||
"AWS_CONTAINER_AUTHORIZATION_TOKEN": "container-token",
|
||||
"AWS_BEARER_TOKEN_BEDROCK": "bedrock-bearer",
|
||||
}
|
||||
result_env = _run_with_env(extra_os_env=aws_vars)
|
||||
|
||||
for var in aws_vars:
|
||||
assert var not in result_env, f"{var} leaked into subprocess env"
|
||||
|
||||
def test_non_registry_provider_vars_are_stripped(self):
|
||||
"""Extra provider vars not in PROVIDER_REGISTRY must also be blocked."""
|
||||
extra_provider_vars = {
|
||||
@ -213,6 +233,28 @@ class TestBlocklistCoverage:
|
||||
f"(provider={pconfig.id}) missing from blocklist"
|
||||
)
|
||||
|
||||
def test_aws_sdk_provider_vars_are_in_blocklist(self):
|
||||
"""auth_type='aws_sdk' providers rely on credential-chain vars, not API keys."""
|
||||
aws_vars = {
|
||||
"AWS_ACCESS_KEY_ID",
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
"AWS_SESSION_TOKEN",
|
||||
"AWS_SECURITY_TOKEN",
|
||||
"AWS_PROFILE",
|
||||
"AWS_DEFAULT_PROFILE",
|
||||
"AWS_SHARED_CREDENTIALS_FILE",
|
||||
"AWS_CONFIG_FILE",
|
||||
"AWS_WEB_IDENTITY_TOKEN_FILE",
|
||||
"AWS_ROLE_ARN",
|
||||
"AWS_ROLE_SESSION_NAME",
|
||||
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
|
||||
"AWS_CONTAINER_CREDENTIALS_FULL_URI",
|
||||
"AWS_CONTAINER_AUTHORIZATION_TOKEN",
|
||||
"AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE",
|
||||
"AWS_BEARER_TOKEN_BEDROCK",
|
||||
}
|
||||
assert aws_vars.issubset(_HERMES_PROVIDER_ENV_BLOCKLIST)
|
||||
|
||||
def test_extra_auth_vars_covered(self):
|
||||
"""Non-registry auth vars (ANTHROPIC_TOKEN, CLAUDE_CODE_OAUTH_TOKEN)
|
||||
must also be in the blocklist."""
|
||||
|
||||
@ -75,6 +75,25 @@ def _resolve_safe_cwd(cwd: str) -> str:
|
||||
# Hermes-internal env vars that should NOT leak into terminal subprocesses.
|
||||
_HERMES_PROVIDER_ENV_FORCE_PREFIX = "_HERMES_FORCE_"
|
||||
|
||||
_AWS_SDK_CREDENTIAL_ENV_VARS = frozenset({
|
||||
"AWS_ACCESS_KEY_ID",
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
"AWS_SESSION_TOKEN",
|
||||
"AWS_SECURITY_TOKEN",
|
||||
"AWS_PROFILE",
|
||||
"AWS_DEFAULT_PROFILE",
|
||||
"AWS_SHARED_CREDENTIALS_FILE",
|
||||
"AWS_CONFIG_FILE",
|
||||
"AWS_WEB_IDENTITY_TOKEN_FILE",
|
||||
"AWS_ROLE_ARN",
|
||||
"AWS_ROLE_SESSION_NAME",
|
||||
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
|
||||
"AWS_CONTAINER_CREDENTIALS_FULL_URI",
|
||||
"AWS_CONTAINER_AUTHORIZATION_TOKEN",
|
||||
"AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE",
|
||||
"AWS_BEARER_TOKEN_BEDROCK",
|
||||
})
|
||||
|
||||
|
||||
def _build_provider_env_blocklist() -> frozenset:
|
||||
"""Derive the blocklist from provider, tool, and gateway config."""
|
||||
@ -84,6 +103,8 @@ def _build_provider_env_blocklist() -> frozenset:
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
for pconfig in PROVIDER_REGISTRY.values():
|
||||
blocked.update(pconfig.api_key_env_vars)
|
||||
if pconfig.auth_type == "aws_sdk":
|
||||
blocked.update(_AWS_SDK_CREDENTIAL_ENV_VARS)
|
||||
if pconfig.base_url_env_var:
|
||||
blocked.add(pconfig.base_url_env_var)
|
||||
except ImportError:
|
||||
|
||||
Reference in New Issue
Block a user