fix(security): redact Fireworks AI API keys in logs
Fireworks AI is a first-class provider in hermes-agent — FIREWORKS_API_KEY is listed in tools/environments/local.py and the provider is selectable via the model picker (api.fireworks.ai in model_metadata, hermes_cli/models.py). Fireworks API keys follow the format fw_<40 alphanumeric chars> and were absent from _PREFIX_PATTERNS in agent/redact.py. The ENV-assignment and Bearer header patterns catch FIREWORKS_API_KEY=fw_... in config output, but a raw key in a stack trace, debug print, or tool error passed through completely unmasked. Four unit tests added to TestFireworksToken covering bare token masking, env assignment, short-prefix false positive, and visible prefix in output.
This commit is contained in:
parent
ea95fdd6d7
commit
c701c6dad7
2 changed files with 23 additions and 0 deletions
|
|
@ -106,6 +106,7 @@ _PREFIX_PATTERNS = [
|
|||
r"brv_[A-Za-z0-9]{10,}", # ByteRover API key
|
||||
r"xai-[A-Za-z0-9]{30,}", # xAI (Grok) API key
|
||||
r"ntn_[A-Za-z0-9]{10,}", # Notion internal integration token
|
||||
r"fw_[A-Za-z0-9]{30,}", # Fireworks AI API key
|
||||
]
|
||||
|
||||
# ENV assignment patterns: KEY=value where KEY contains a secret-like name.
|
||||
|
|
|
|||
|
|
@ -886,3 +886,25 @@ class TestFileReadNonReusableRedaction:
|
|||
out = redact_sensitive_text(f"key: {self.SK}", force=True, file_read=True)
|
||||
assert "«redacted:sk-…»" in out
|
||||
assert self.SK not in out
|
||||
|
||||
|
||||
class TestFireworksToken:
|
||||
KEY = "fw_" + "A" * 40
|
||||
|
||||
def test_bare_token_masked(self):
|
||||
result = redact_sensitive_text(f"fireworks error: key {self.KEY}", force=True)
|
||||
assert self.KEY not in result
|
||||
assert "fw_AA" in result
|
||||
|
||||
def test_env_assignment_masked(self):
|
||||
result = redact_sensitive_text(f"FIREWORKS_API_KEY={self.KEY}", force=True)
|
||||
assert self.KEY not in result
|
||||
|
||||
def test_too_short_not_masked(self):
|
||||
short = "fw_tooshort"
|
||||
result = redact_sensitive_text(f"text {short} here", force=True)
|
||||
assert short in result
|
||||
|
||||
def test_prefix_visible_in_masked_output(self):
|
||||
result = redact_sensitive_text(self.KEY, force=True)
|
||||
assert result.startswith("fw_AA")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue