Skip to content

fix(security): consolidated security hardening — SSRF, timing attack, tar traversal, credential leakage - #5944

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-701b2186
Apr 8, 2026
Merged

fix(security): consolidated security hardening — SSRF, timing attack, tar traversal, credential leakage#5944
teknium1 merged 1 commit into
mainfrom
hermes/hermes-701b2186

Conversation

@teknium1

@teknium1 teknium1 commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Salvaged and extended fixes from 4 security PRs into a single consolidated PR.

What this PR does

① Timing attack prevention (from #5800 by @memosr)

  • Replace token == self._api_key with hmac.compare_digest() in API server auth
  • 2-line fix, stdlib only

② Docker credential leakage (from #5806 by @memosr)

  • Apply _HERMES_PROVIDER_ENV_BLOCKLIST to Docker env forwarding
  • local.py already had this; docker.py was missing it
  • 130 provider credentials now blocked from leaking into containers

③ Tar path traversal (from #5928 by @Awsh1)

  • Replace unsafe tar.extractall() with _safe_extract_tar() in TerminalBench2
  • Rejects: path traversal (../), absolute paths, symlinks, non-file members
  • CVE-2007-4559 mitigation
  • Added security test suite

④ SSRF protection (extended from #5915 by @Ruzzgar)

  • Original PR only fixed Discord; extended to ALL 9 vulnerable platform adapters
  • Defense in depth: is_safe_url() added to both shared helpers in base.py AND each adapter
  • Blocks internal/private network URLs (127.0.0.1, 169.254.169.254, 10.x, 192.168.x, etc.)
  • Unsafe URLs fall back to text send instead of server-side fetch

Protected adapters:

Adapter Protection point
base.py cache_image_from_url(), cache_audio_from_url()
Discord send_image() before aiohttp download
Slack send_image() before httpx download
Telegram send_image() before URL pass-through + httpx fallback
Matrix send_image() before aiohttp/httpx download
Mattermost _send_url_as_file() before aiohttp download
Feishu _download_remote_document() before httpx download
WeCom _download_remote_bytes() before httpx stream
Signal via cache_image_from_url() in base.py
WhatsApp via cache_image_from_url() in base.py

Files changed (14 files, +284/-11)

  • gateway/platforms/api_server.py — hmac.compare_digest
  • tools/environments/docker.py — env var blocklist
  • environments/benchmarks/terminalbench_2/terminalbench2_env.py — safe tar extraction
  • gateway/platforms/base.py — SSRF in cache helpers
  • gateway/platforms/{discord,slack,telegram,matrix,mattermost,feishu,wecom}.py — SSRF in adapters
  • tests/environments/benchmarks/test_terminalbench2_env_security.py — new security tests
  • tests/gateway/test_mattermost.py, tests/gateway/test_media_download_retry.py — mock is_safe_url

Test results

  • 216 targeted tests pass (API server, URL safety, Discord send, Mattermost, media retry, TB2 security)
  • 2095 gateway tests pass (10 pre-existing failures unrelated to this PR)
  • E2E validation of all 4 fixes passed

Closes #5800, #5806, #5915, #5928.

… tar traversal, credential leakage

Salvaged from PRs #5800 (memosr), #5806 (memosr), #5915 (Ruzzgar), #5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
@github-actions

github-actions Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

⚠️ Supply Chain Risk Detected

This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.

⚠️ WARNING: base64 encoding/decoding detected

Base64 has legitimate uses (images, JWT, etc.) but is also commonly used to obfuscate malicious payloads. Verify the usage is appropriate.

Matches (first 20):

974:+    return base64.b64encode(buf.getvalue()).decode("ascii")

Automated scan triggered by supply-chain-audit. If this is a false positive, a maintainer can approve after manual review.

@teknium1
teknium1 merged commit 469cd16 into main Apr 8, 2026
3 of 4 checks passed
saxster pushed a commit to saxster/hermes-agent that referenced this pull request Apr 8, 2026
… tar traversal, credential leakage (NousResearch#5944)

Salvaged from PRs NousResearch#5800 (memosr), NousResearch#5806 (memosr), NousResearch#5915 (Ruzzgar), NousResearch#5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
rivercrab26 added a commit to rivercrab26/hermes-agent that referenced this pull request Apr 9, 2026
Discord attachment uploads silently break for users behind DNS-rewriting
proxies (Clash/Mihomo fake-ip mode). The proxy resolves cdn.discordapp.com
to a fake 198.18.x.x address from the IETF benchmark range (RFC 6890), so
the SSRF guard added in NousResearch#5944 rejects every attachment as "unsafe".

Symptom in the gateway log:
  [Discord] Failed to cache image attachment:
  Blocked unsafe URL (SSRF protection): https://cdn.discordapp.com/...

Root cause: cache_image_from_url / cache_audio_from_url validate the
resolved IP, but Discord attachment URLs come straight from discord.py,
which has already authenticated with the platform. The IP-based check is
both unreliable (DNS rewriting) and unnecessary (URL is already trusted).

Fix: add a `trusted_source` parameter that opts out of the SSRF check.
Discord's inbound attachment handler passes trusted_source=True. The
default remains False so agent-supplied URLs (e.g. send_image with a
user-provided link) keep the safety check.

Tests:
- 4 new tests in TestTrustedSourceBypass covering both helpers
- Add an autouse _mock_safe_url fixture to TestCacheImageFromUrl /
  TestCacheAudioFromUrl so the existing retry tests do not depend on
  the developer local DNS resolver (which previously failed under fake-ip)

Verified: 37/37 media-cache tests pass, no other regressions in
tests/gateway/.
Tommyeds pushed a commit to Tommyeds/hermes-agent that referenced this pull request Apr 12, 2026
… tar traversal, credential leakage (NousResearch#5944)

Salvaged from PRs NousResearch#5800 (memosr), NousResearch#5806 (memosr), NousResearch#5915 (Ruzzgar), NousResearch#5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
@ether-btc

Copy link
Copy Markdown
Contributor

Excellence Contribution — Consolidated Security Hardening

What it does
Salvaged and extended fixes from 4 security PRs into one consolidated merge, addressing 4 distinct vulnerability classes across 14 files:

① Timing attack prevention — API server auth replaced token == self._api_key with hmac.compare_digest(). String equality comparison leaks timing information exploitable to guess API keys. hmac.compare_digest is constant-time and eliminates the oracle. (Scoped to gateway/platforms/api_server.py auth — not a blanket fix for all key comparisons in the codebase.)

② Docker credential leakagedocker.py was missing the _HERMES_PROVIDER_ENV_BLOCKLIST that local.py already applied. 130 provider credential env vars were forwarded into containers on every local subprocess execution. Blocklist now applied to Docker env forwarding as well.

③ Tar path traversal (CVE-2007-4559 mitigation)TerminalBench2 used tar.extractall() which can write files outside the target directory. Replaced with _safe_extract_tar() which rejects: path traversal, absolute paths, symlinks, and non-file members.

④ SSRF protection (extended to all 9 adapters) — Media download functions on Discord, Slack, Telegram, Matrix, Mattermost, Feishu, WeCom, Signal, and WhatsApp all accepted arbitrary URLs. is_safe_url() now blocks internal/private network ranges (127.0.0.1, 169.254.169.254, 10.x, 192.168.x, etc.); unsafe URLs fall back to text display instead of server-side fetch.

Protected adapters: base.py (shared helpers), Discord, Slack, Telegram, Matrix, Mattermost, Feishu, WeCom, Signal, WhatsApp.

Implications

  • Every externally-facing deployment was vulnerable to at least one of these before the fix
  • SSRF enables internal service fingerprinting and AWS metadata credential theft via http://169.254.169.254/ — a well-documented real attack chain
  • The hmac.compare_digest change is a one-line stdlib swap with zero behavioral change for legitimate users
  • Docker credential blocklist limits the blast radius of a container escape scenario

angelburgosrosado pushed a commit to angelburgosrosado/hermes-agent that referenced this pull request Apr 27, 2026
… tar traversal, credential leakage (NousResearch#5944)

Salvaged from PRs NousResearch#5800 (memosr), NousResearch#5806 (memosr), NousResearch#5915 (Ruzzgar), NousResearch#5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
… tar traversal, credential leakage (NousResearch#5944)

Salvaged from PRs NousResearch#5800 (memosr), NousResearch#5806 (memosr), NousResearch#5915 (Ruzzgar), NousResearch#5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
… tar traversal, credential leakage (NousResearch#5944)

Salvaged from PRs NousResearch#5800 (memosr), NousResearch#5806 (memosr), NousResearch#5915 (Ruzzgar), NousResearch#5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
… tar traversal, credential leakage (NousResearch#5944)

Salvaged from PRs NousResearch#5800 (memosr), NousResearch#5806 (memosr), NousResearch#5915 (Ruzzgar), NousResearch#5928 (Awsh1).

Changes:
- Use hmac.compare_digest for API key comparison (timing attack prevention)
- Apply provider env var blocklist to Docker containers (credential leakage)
- Replace tar.extractall() with safe extraction in TerminalBench2 (CVE-2007-4559)
- Add SSRF protection via is_safe_url to ALL platform adapters:
  base.py (cache_image_from_url, cache_audio_from_url),
  discord, slack, telegram, matrix, mattermost, feishu, wecom
  (Signal and WhatsApp protected via base.py helpers)
- Update tests: mock is_safe_url in Mattermost download tests
- Add security tests for tar extraction (traversal, symlinks, safe files)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants