Skip to content
agentblog
Go back

Nobody Configured It. Hermes Agent Phoned Parallel Anyway.

.md
TL;DR

A Parallel.ai employee (GitHub @NormallyGaussian, commit email mharris@parallel.ai) submitted 161 pull requests across 14+ open-source agent projects adding Parallel as a web search backend. Of the ten that merged, one disclosed the employment relationship. In NousResearch’s Hermes Agent the change made search.parallel.ai/mcp the zero-config default, so a fresh install with no API key and no configuration sent every web_search and web_extract call to a third party. Founder teknium1 merged it in 4.5 hours with zero reviews on 11 June; it was reported on 12 June, triaged P3, “cosmetic, nice to have”, and reverted on 14 June. If you run Hermes or OpenClaw, set your web backends explicitly and check your egress logs.

On 12 June a Hermes Agent user filed issue #45058 with an unglamorous observation: their agent was making outbound calls to search.parallel.ai. They had configured no web backend. They held no API key for anything. The traffic went out regardless.

That is the whole vulnerability. There is no memory corruption, no injected payload, no obfuscated dependency. Someone changed a default value in a config resolver, and roughly a fifth of a million stars’ worth of installed agent quietly acquired a new upstream.

What actually changed

Before commit e0e2571, Hermes Agent’s backend auto-detection fell through to firecrawl when nothing was configured. Firecrawl needs a key, so the call failed at invocation time. Ugly, but honest: the tool told you it wasn’t set up.

After the commit, the terminal fallback became Parallel’s free hosted Search MCP. No PARALLEL_API_KEY required, because Parallel made the endpoint keyless in April. So the failure mode inverted. Instead of erroring, the agent worked, and every query went to a company the user had never heard of. Two follow-up commits (93764b9, 0a5762c) hardened the default against override.

The provenance is where it gets interesting. The change arrived as PR #34971 from @NormallyGaussian and was closed unmerged. Days later teknium1, the NousResearch founder, opened PR #43798 titled “Salvages #34971 by @NormallyGaussian with authorship preserved,” and merged it 4.5 hours later with zero reviews and zero comments. The commit lists Matt Harris <mharris@parallel.ai> as author and Teknium as committer. Part of the same diff added "mharris@parallel.ai": "NormallyGaussian" to scripts/release.py, so the employer domain is sitting in the repo’s own author map.

@NormallyGaussian’s GitHub bio reads “Currently at @parallel-web.” The PR description never mentioned it.

One contributor, 161 pull requests

An anonymous researcher documented the pattern in a gist on 14 June. Every one of @NormallyGaussian’s 161 PRs is Parallel-related. Zero non-Parallel contributions. Ten merged across six repos, and exactly one, agno #7857 (“Note: I work for Parallel.”), disclosed the relationship.

OpenClaw shows the persistence. Six PRs between January and March, all rejected. Then #85158 landed on 22 May with zero reviews, and the next three sailed through, including #90849: “add free Parallel Search MCP as the zero-config default web_search provider.” Auto-detect order 76, deliberately ahead of DuckDuckGo’s 100.

Parallel’s April launch post for the keyless MCP named its targets outright: “free by default for agents and AI tools like Cursor, Claude Code, OpenClaw, Hermes Agent, and OpenCode.” Same post ships a copy-paste prompt instructing your coding agent to install Parallel into its own MCP config. The company also hosts parallel.ai/agents.md, a page written for agents to read. The distribution channel is the agent itself.

OpenClaw’s review bot called it. A human overrode it.

On 6 June, OpenClaw’s clawsweeper Codex bot posted a full analysis on #90849 flagging two P1 risks:

Quote

Existing no-provider/keyless web_search users would silently move from DuckDuckGo to Parallel’s hosted Search MCP and a new outbound host unless maintainers explicitly accept that default change.

Its verdict on whether this was the right approach: “No, not as-is.” Its recommended option: land the provider as explicitly selectable first. Its security section cleared the code itself while noting “the default-host switch remains a compatibility/privacy merge risk.”

Merged the next day by davemorin. Zero human reviews.

Why a security team should care

Three things, in ascending order of severity.

Query content is data egress. Agent search queries carry internal hostnames, error strings, package versions, customer names, and half-written code. A default that ships them to an unauthenticated endpoint creates an undeclared data processor in every environment running the tool. There is no account, no contract, no DPA, and no way to ask what was sent.

Search results are a write channel into the context window. Whoever answers web_search decides what text the model reads and acts on. That is the same lethal trifecta shape: untrusted content, private data access, and an outbound path, with the untrusted-content leg handed to a default nobody chose. Compromise the search provider and you get direct write access to the reasoning of every agent that fell through to it.

Defaults are invisible to your tooling. No scanner models “which URL does the config resolver terminate at” as a trust boundary. SCA watches dependency manifests; secret scanners watch for keys. A one-line change to auto-detect ordering, submitted by a helpful contributor with a real name and a plausible commit history, passes every gate you have. In a repo carrying 5,000+ open PRs, the small config change is the least-scrutinised diff in the tree, and the harness is the security boundary now.

Triaged as cosmetic, fixed in two days

Hermes maintainers labelled #45058 P3, a priority whose description reads “cosmetic, nice to have.” The issue drew 19 👍 and 10 😕, plus comments like vektorprime’s: “This is a huge concern. This organization must not be allowed to play us for their profit.”

Credit where due: two weeks ago, on 14 June, teknium1 merged PR #46350, removing the keyless fallback and restoring the requirement for explicit configuration. Three days from merge to revert is a good number.

The residue is the part that lasts. Five copycat PRs from unrelated developers are now open or merged in other projects, one citing “Hermes preference order” as justification and another “modeled on OpenClaw’s equivalents.” A default that survives a fortnight in a popular repo becomes precedent everywhere else.

If you run Hermes Agent, set your web backends explicitly in every profile, since explicit config stops auto-detect before it can reach a keyless fallback:

Example
# ~/.hermes/config.yaml and ~/.hermes/profiles/*/config.yaml
web:
  backend: searxng
  search_backend: searxng
  extract_backend: ddgs

SearXNG and DDGS are search-only, so web_extract will fail cleanly. That is the point. Blocking the silent route first, sorting out extract on your own terms second.

Then go read your egress logs. The question worth asking about an agent has moved from what its code does to who it talks to when you never told it to talk to anyone.

Sources

Related on this blog



Previous Post
Ralph Is Five Lines of Bash. All the Bugs Are in the Improvements.
Next Post
Agent Harnesses: A Standard for a Word Nobody Agrees On